2020牛客暑期多校训练营(第三场)H Sort the Strings Revision 题解
题意:
原串为长度为n(2e6)的 012345678901……
每次将p[i]位置修改为d[i]形成一个新的串,然后继续在新的串上操作,共n次。
求总共n+1个串的排名
这道题上来一看毫无头绪,考场上也就没细想……
这道题有一个很美妙的性质,就是p[i]是一个排列,这就意味着每个位置只会改变一次,那么我们可以p[i1]=1,p[i2]=2,p[i3]=3……的顺序对这些序列进行处理。
所以我们采用类似快速排序的方式,找到当前区间p[i]的最小值,看d[i]与p[i]%10的关系,如果d[i]=p[i]%10,说明没变,跳过,否则如果d[i]<p[i]%10,则所有比 i 大的串字典序都比 i 小的串字典序小,反之亦然。
一开始我找区间最小值的时候用的是线段是,脸黑,T最后5%,改成了笛卡尔树才过……
值得注意的是,在操作完后排名可能会有重复的,这时候我们需要采用类似后缀数组中的桶排的方式以第一次排序结果为第一关键字,以位置为第二关键字进行排序。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 #define N 2000005 8 using namespace std; 9 int T,n,ps,pa,pb,pm,p[N]; 10 int ds,da,db,dm,d[N]; 11 struct no{ 12 int left,right,mid; 13 int mn; 14 }node[N*4]; 15 void build(int left,int right,int x) 16 { 17 node[x].left=left,node[x].right=right; 18 if(left==right) 19 { 20 node[x].mn=left; 21 return; 22 } 23 int mid=(left+right)>>1; 24 node[x].mid=mid; 25 build(left,mid,x<<1); 26 build(mid+1,right,x<<1|1); 27 if(p[node[x<<1].mn]<p[node[x<<1|1].mn]) node[x].mn=node[x<<1].mn; 28 else node[x].mn=node[x<<1|1].mn; 29 } 30 int Mn; 31 inline void get(int left,int right,int x) 32 { 33 if(node[x].left==left&&node[x].right==right) 34 { 35 if(p[node[x].mn]<p[Mn]) 36 { 37 Mn=node[x].mn; 38 } 39 return; 40 } 41 int mid=node[x].mid; 42 if(left>mid) get(left,right,x<<1|1); 43 else if(right<=mid) get(left,right,x<<1); 44 else get(left,mid,x<<1),get(mid+1,right,x<<1|1); 45 } 46 int rnk[N],ls[N],rs[N]; 47 void solve(int left,int right,int tmp) 48 { 49 if(right<=left)return; 50 if(p[tmp]==N)return; 51 if(p[tmp]%10>d[tmp]) 52 { 53 rnk[left]+=right-tmp; 54 rnk[tmp+1]-=right-tmp; 55 } 56 else 57 { 58 rnk[tmp+1]+=tmp-left+1; 59 rnk[right+1]-=tmp-left+1; 60 } 61 solve(left,tmp,ls[tmp]); solve(tmp+1,right,rs[tmp]); 62 } 63 int num[N],Sa[N],st[N],top,rt; 64 int main() 65 { 66 scanf("%d",&T); 67 while(T--) 68 { 69 scanf("%d",&n); 70 scanf("%d%d%d%d",&ps,&pa,&pb,&pm); 71 for(register int i=0;i<n;++i) p[i]=i; 72 for(register int i=1;i<=n-1;++i) 73 { 74 swap(p[i],p[ps%(i+1)]); 75 ps=1ll*(1ll*ps*pa+1ll*pb)%pm; 76 } 77 78 scanf("%d%d%d%d",&ds,&da,&db,&dm); 79 for(register int i=0;i<n;++i) 80 { 81 d[i]=ds%10; 82 ds=1ll*(1ll*ds*da+db)%dm; 83 } 84 85 for(register int i=0;i<n;++i) 86 { 87 if(p[i]%10==d[i]) p[i]=N; 88 rnk[i]=0; 89 } 90 91 rnk[n]=0; 92 p[n+1]=N+5; 93 rt=0,top=0; 94 for(int i=0;i<n;i++) 95 { 96 if(p[i]<p[rt]) rt=i; 97 int k=top; 98 while(top&&p[st[top]]>p[i]) top--; 99 if(top) rs[st[top]]=i; 100 if(top<k) ls[i]=st[top+1]; 101 top++; 102 st[top]=i; 103 } 104 solve(0,n,rt); 105 for(register int i=0;i<=n;++i) num[i]=0; 106 for(register int i=1;i<=n;++i)rnk[i]+=rnk[i-1]; 107 for(register int i=0;i<=n;++i) num[rnk[i]]++; 108 for(register int i=1,m=n+2;i<=m;++i) num[i]+=num[i-1]; 109 for(register int i=n;i>=0;--i) 110 { 111 Sa[--num[rnk[i]]]=i; 112 } 113 for(register int i=0;i<=n;++i) rnk[Sa[i]]=i; 114 long long ans=0,xp=1; 115 for(register int i=0;i<=n;++i) 116 { 117 ans=(ans+1ll*rnk[i]*xp%1000000007)%1000000007; 118 xp=xp*10000019%1000000007; 119 } 120 printf("%lld\n",ans); 121 } 122 return 0; 123 }