解题:CF1063F String Journey

题面

分析性质以进行DP

性质1:一定有一个最优解通过每次删除第一个或最后一个字符达到

这个脑补一下就能证明了

那么我们设$dp[i]$表示后缀$[i,n]$选出一个前缀所能达到的最大长度,从右往左DP

转移时二分当前DP值$dp[i]$,在右边找有没有大于等于$f_i-1$且是$[i,n]$前缀/后缀的DP值,具体怎么找就看个人了

可以不二分吗?可以,继续分析得到性质2

性质2:dp[i]<=dp[i+1]+1

反证,如果$dp[i]>dp[i+1]+1$,那么删掉第一个字符,就会得到$dp[i+1]>dp[i+1]+1-1$

然而不想(hui)写后缀结构的我选择了暴力查哈希,因为答案不会超过$sqrt n$,所以从小到大枚举长度做即可 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define uint unsigned int
 5 using namespace std;
 6 const int N=500005;
 7 const uint mod=7539151;
 8 bool p1[N],p2[N],mp[mod+1]; 
 9 uint hsh[N]; char str[N]; int n; 
10 int main()
11 {
12     register int i,j;
13     scanf("%d%s",&n,str+1);
14     bool *dp=p1,*pd=p2; 
15     int ans=1,lim=min(1000,n);
16     for(i=1;i<=n;i++) 
17         hsh[i]=str[i]-'a'+1,pd[i]=true;
18     for(i=2;i<=lim;swap(dp,pd),i++)
19     {
20         memset(dp,0,sizeof p1);
21         memset(mp,0,sizeof mp);
22         for(j=n-i+1;j;j--)
23         {
24             if(j+i<=n&&pd[j+i]) mp[hsh[j+i]]=true;
25             if(mp[hsh[j]]||mp[hsh[j+1]]) ans=i,dp[j]=true;
26         }
27         for(j=1;j<=n-i+1;j++)
28             hsh[j]=(hsh[j]*233+str[j+i-1]-'a'+1)%mod;
29     }
30     printf("%d",ans);
31     return 0;
32 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/10534938.html