题意:
给你一个长度为n的串s0,然后现在有一个长度为n的排列p和一个长度为n的d,从0开始到n-1,每次都有一个操作:
,然后替换掉
的第p[i]个字符为d[i]。问你这n+1个字符串的字典序。
题解:
太强了,根本想不到啊
首先以位置为顺序,p的大小为优先级建立笛卡尔树,注意如果d[i]==p[i]%10,就是说如果改了这个点的值根没改一样,那么就将p[i]设为inf,表示它一定是最后的,在这道题,表示它统治的区间就是它这个点本身。
笛卡尔树建立完以后,每个点表示它统治的区间:
就比如红色点的修改只会影响到在红色点区间内的值的排名,因为最上面那个黑色的点修改了之后,要么就是在它之后修改的数比前面的数全都大,要么就是全都小,所以红色点修改的情况不会影响到蓝色的点(自行理解一下)。
然后考虑每个区间的排名,拿红色的点举例子,如果它修改的值比原来的值要小,那么在这个位置之后修改的位置,一定比这个区间内在这个位置之前修改的值都要小。
所以dfs(l,root,ls[root],no+(p[root]%10>d[root])*(r-root));
反之亦然。
并且修改一个位置,会影响到下一个位置的排名,所以dfs的时候不是(l,root-1)而是(l,root)。
如果当前p[root]==inf的话,表示它所统治的区间,所有值都是不变的,那么就按照位置顺序排名。
tql/QAQ.jpg
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e6+5;
const ll mod=1e9+7,sed=10000019;
int ls[N],rs[N],fa[N],st[N],top,p[N],d[N];
int n;
void build(){
for(int i=0;i<n;i++){
int f=0;
while(top&&p[st[top]]>p[i])
top--,f=1;
if(top)fa[i]=st[top],rs[st[top]]=i;
if(f)ls[i]=st[top+1],fa[ls[i]]=i;
st[++top]=i;
}
}
ll ans[N];
void dfs(int l,int r,int root,int no){
if(l==r){
ans[l]=no;
return ;
}
if(p[root]==n){
for(int i=0;i<=r-l+1;i++)
ans[l+i]=no+i;
return ;
}
dfs(l,root,ls[root],no+(p[root]%10>d[root])*(r-root));
dfs(root+1,r,rs[root],no+(p[root]%10<d[root])*(root-l+1));
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=0;i<n;i++)ls[i]=rs[i]=fa[i]=0;
top=0;
int ps,pa,pb,pm;
scanf("%d%d%d%d",&ps,&pa,&pb,&pm);
for(int i=0;i<n;i++)p[i]=i;
for(int i=1;i<n;i++)
swap(p[ps%(i+1)],p[i]),ps=(1ll*ps*pa+pb)%pm;
scanf("%d%d%d%d",&ps,&pa,&pb,&pm);
for(int i=0;i<n;i++)
d[i]=ps%10,ps=(1ll*ps*pa+pb)%pm,p[i]=d[i]==p[i]%10?n:p[i];
build();
dfs(0,n,st[1],0);
ll mul=1,sum=0;
for(int i=0;i<=n;i++)
sum=(sum+ans[i]*mul)%mod,mul=mul*sed%mod;
printf("%lld\n",sum);
}
return 0;
}