1. 程式人生 > 實用技巧 >[nowcoder5668H]Sort the Strings Revision

[nowcoder5668H]Sort the Strings Revision

考慮對於$p_{i}=0$,那麼可以快速比較出$s_{0},s_{1},...,s_{i-1}$與$s_{i},s_{i+1},...,s_{n}$之間的大小關係,然後對兩邊分別找到最小的$p_{i}$即可,用線段樹維護複雜度多了一個log無法通過,因此需要用笛卡爾樹來維護 笛卡爾樹:https://oi-wiki.org/ds/cartesian-tree/ 搜尋時維護在其前面的數量,即要求出笛卡爾樹的子樹大小,另外需要特殊處理$d[i]=s_{0}[p[i]]$的情況,可以令$p[i]=n$,還有當兩個字串相同時編號小的優先
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 2000005
 4 #define mod 1000000007
 5 int t,n,p[N],d[N],st[N],ls[N],rs[N],rk[N];
 6 void dfs(int k,int l,int r,int s){
 7     if ((p[k]==n)||(l>=r)){
 8         for(int i=l;i<=r;i++)rk[i]=s+(i-l);
 9         return;
10     }
11     dfs(ls[k],l,k,s+(p[k]%10
>d[k])*(r-k)); 12 dfs(rs[k],k+1,r,s+(p[k]%10<d[k])*(k-l+1)); 13 } 14 int main(){ 15 scanf("%d",&t); 16 while (t--){ 17 scanf("%d",&n); 18 int p1,p2,p3,p4; 19 scanf("%d%d%d%d",&p1,&p2,&p3,&p4); 20 for(int i=0;i<n;i++)p[i]=i; 21
for(int i=1;i<n;i++){ 22 swap(p[p1%(i+1)],p[i]); 23 p1=(1LL*p1*p2+p3)%p4; 24 } 25 int d1,d2,d3,d4; 26 scanf("%d%d%d%d",&d1,&d2,&d3,&d4); 27 for(int i=0;i<n;i++){ 28 d[i]=d1%10; 29 d1=(1LL*d1*d2+d3)%d4;
30 if (p[i]%10==d[i])p[i]=n; 31 } 32 st[0]=0; 33 for(int i=0;i<n;i++){ 34 int k=st[0]; 35 while ((k>0)&&(p[st[k]]>p[i]))k--; 36 if (k)rs[st[k]]=i; 37 if (k<st[0])ls[i]=st[k+1]; 38 st[++k]=i; 39 st[0]=k; 40 } 41 dfs(st[1],0,n,0); 42 int s=1,ans=0; 43 for(int i=0;i<=n;i++){ 44 ans=(ans+1LL*s*rk[i])%mod; 45 s=s*10000019LL%mod; 46 } 47 printf("%d\n",ans); 48 } 49 }
View Code