题目大意:
给你一个串,问你这个串现在的顺序是不是不是最小表示法的串
做法:
一开始打算暴力,但是仔细想想,发现,暴力很可能卡成,导致凉凉。【比如给一个长度为n的串里面的每个字母都一样】
一般来说,这道题应该属于字符串类型,需要使用字符串算法。
但是!
作为一个菜鸡,怎么会打字符串算法呢?/x
所以,这里就用上了我之前yy出来的一个算法:分块求字符串区间
how?
我们知道,c++提供了一个变量:string,它支持对string,char的'+'操作,而且复杂度是O(1)的,所以,我们可以按分块的思想,开个string数组,每个数组存的是第i个块中的所有字符形成的字符串。
这样,如果我们要搞出区间为[l,r]的字符串,我们就可以先判断下,假设两个点所属的块相同或相邻,我们暴力合并出串,否则,我们先对左边块暴力合并,中间块直接调用数组合并,再暴力合并右边块,就用的时间合并出了我们想要的块,而且,不难证明,该方法空间复杂度也是优秀的
代码
#include<bits/stdc++.h> using namespace std; const int N=318,M=1e5+1; string s[N];int b[M]; string x;int n,block; inline string get_string(int l,int r){ string res=""; if(b[r]-b[l]<=1){ for(int i=l;i<=r;++i){ res+=x[i-1]; } return res; } for(int i=l;i<=(b[l]*block);++i){ res+=x[i-1]; } for(int i=b[l]+1;i<b[r];++i){ res+=s[i]; } for(int i=(b[r]-1)*block+1;i<=r;++i){ res+=x[i-1]; } return res; } int main(){ //最小表示法?NO!分块拼表?先试试卡时优化~哈哈 scanf("%d",&n); block=sqrt(n); cin>>x; for(int i=1;i<=n;++i){ b[i]=(i-1)/block+1; s[b[i]]+=x[i-1]; } for(int i=2;i<=n;++i){//以i为开头 if(x[i-1]<x[0]){ puts("YES"); return 0; } if(x[i-1]>x[0]){ continue; } string y=get_string(i,n)+get_string(1,i-1); if(y<x){ puts("YES"); return 0; } } puts("NO"); return 0; }