[noi34]palindrome

分割实际上就是不断地从两端取出一样的一段,并对剩下的串进行分割。下面我们来证明一下每一次贪心取出最短一段的正确性:

考虑两种分割方式,分别表示成S=A+B+A和S=C+D+C,其中A就是最短的一段,那么当2|A|<|C|,显然就有C=A+E+A,那么就可以用三次划分来完成C,而当|A|<|C|<2|A|,即AC中重叠了,那么最短的前缀一定不是A,而是重叠部分(重叠部分既是A的前缀又是A的后缀)。

那么这个贪心就成立了,用hash暴力判断即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 1000000007
 4 #define ll long long
 5 #define N 1000001
 6 int t,l;
 7 ll sum[N],mi[N];
 8 char s[N];
 9 ll calc(int l,int r){
10      return ((sum[r]-sum[l-1]*mi[r-l+1])%mod+mod)%mod;
11 }
12 int work(int l,int r){
13     if (l>r)return 0;
14     int mid=(l+r+1>>1),k=l;
15     while ((k<mid)&&(calc(l,k)!=calc(l+r-k,r)))k++;
16     if (k==mid)return 1;
17     return work(k+1,l+r-k-1)+2;
18 }
19 int main(){
20      mi[0]=1;
21      for(int i=1;i<N;i++)mi[i]=(mi[i-1]*29)%mod;
22      scanf("%d",&t);
23      while (t--){
24           scanf("%s",s);
25           l=strlen(s);
26           sum[0]=s[0]-'a'+1;
27           for(int i=1;i<l;i++)sum[i]=(sum[i-1]*29+s[i]-'a'+1)%mod;
28           printf("%d\n",work(0,l-1));
29      }
30 }
View Code

猜你喜欢

转载自www.cnblogs.com/PYWBKTDA/p/11272226.html
34