2020牛客暑期多校訓練營(第三場)H Sort the Strings Revision 題解
阿新 • • 發佈:2020-07-22
題意:
原串為長度為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> 7View Code#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 }