这道题改题时我打了个玄学复杂度的暴力,然后成功的时间最短,内存最小,然后我成功的造了一组数据hack掉了自己的代码。。。。
通过观察,我们可以很容易的发现在操作几次后,整个序列就会变成一块一块相同的字母。
于是我们可以对我们的暴力做一些优化:在将字母塞进桶中时,不是一个一个往里塞,而是将一段连续的区间O(1)塞进桶中。
实现也很简单:在每次操作后,存下每个块的左右端点,塞进去的时候注意把包含l,r的块断开,即可愉快的AC并且代码跑的快的飞起。
但是有一个问题:处理l,r所在块的边界时,需要暴力找到这两个块的边界,如果块特别大,那么每次寻找都是O(n)的,然后就愉快的T了(反正我自己造的100000个a跑了6s)
附超快AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 inline long long read() 4 { 5 int x=0,f=1; 6 char ch=getchar(); 7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 8 while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); 9 return x*f; 10 } 11 int n,m,pre[100005],la,tong[27],a[100005],ne[100005],sum; 12 char s[100005]; 13 int main() 14 { 15 n=read(),m=read(); 16 cin>>s+1; 17 memset(a,-1,sizeof(a)); 18 la=1,a[1]=s[1]-'a'; 19 for(int i=2;i<=n;i++) 20 if(s[i]==s[i-1]) 21 ne[i]=0; 22 else ne[la]=i-1,la=i,a[i]=s[i]-'a'; 23 ne[la]=n; 24 for(int kk=1;kk<=m;kk++) 25 { 26 int l=read(),r=read(),x=read(),laa; 27 if(!ne[r+1]&&r!=n) 28 for(int i=r;i;i--) 29 if(ne[i]) 30 { 31 ne[r+1]=ne[i]; 32 a[r+1]=a[i]; 33 ne[i]=r; 34 break; 35 } 36 for(int i=l;i;i--) 37 if(ne[i]) 38 { 39 laa=ne[i]+1; 40 tong[a[i]]=laa-l; 41 if(i!=l)ne[i]=l-1; 42 break; 43 } 44 while(laa<=r) 45 { 46 tong[a[laa]]+=min(ne[laa],r)-laa+1; 47 int nex=min(ne[laa],r); 48 ne[laa]=0,a[laa]=-1,laa=nex+1; 49 } 50 if(x==0) 51 for(int i=25;i>=0;i--) 52 if(tong[i]) 53 { 54 a[l]=i; 55 ne[l]=l+tong[i]-1; 56 l+=tong[i]; 57 tong[i]=0; 58 } 59 if(x==1) 60 for(int i=0;i<=25;i++) 61 if(tong[i]) 62 { 63 a[l]=i; 64 ne[l]=l+tong[i]-1; 65 l+=tong[i]; 66 tong[i]=0; 67 } 68 } 69 for(int i=1;i<=n;i++) 70 { 71 if(a[i]==-1) 72 a[i]=a[i-1]; 73 putchar(a[i]+'a'); 74 } 75 puts(""); 76 return 0; 77 }