hdu 5340(manacher+枚举)
生活随笔
收集整理的這篇文章主要介紹了
hdu 5340(manacher+枚举)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=5340
解題思路:首先用manacher處理每個字符,接下來就是要枚舉了。
首先是我想到的dp,dp[i][j]表示第i個字符結尾的第j個回文串是否存在。
dp[i+k-1][j] = 1 if(dp[i-k+1][j-1] == 1),k當前表示回文串的半徑長度?
最后只需要判斷dp[len][3]即可。
但很可惜超時了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std;const int maxn = 20005; int p[maxn<<1],dp[maxn<<1][4]; char str[maxn],c[maxn];void manacher(int len) {int id = 0;p[0] = 1;for(int i = 1; i <= 2 * len; i++){if(id + p[id] > i) p[i] = min(p[2*id-i],id + p[id] - i);else p[i] = 1;while(i-p[i]>=0 && i+p[i]<=2*len && c[i-p[i]]==c[i+p[i]]) p[i]++;if(i+p[i] > id+p[id])id = i;} }int main() {int t;scanf("%d",&t);while(t--){memset(dp,0,sizeof(dp));scanf("%s",str+1);int len = strlen(str+1);c[0] = '#';for(int i = 1; i <= len; i++){c[2*i-1] = str[i];c[2*i] = '#';}manacher(len);dp[0][0] = 1;for(int i = 1; i < 2 * len; i++)for(int j = 1 + (i % 2 == 0); j <= p[i]; j++)for(int k = 1; k <= 3; k++){if(dp[i - j + 1][k-1])dp[i + j - 1][k] = 1;}if(dp[2*len][3])printf("Yes\n");else printf("No\n");}return 0; }其實這里可以枚舉第一個串和第三個串的末尾和起始位置,這樣就只需要判斷中間位置的串是否是回文即可。 #include <cstdio> #include <algorithm> #define MAXN 20010 using namespace std;int n; char d[MAXN];///原始字符串 char st[MAXN*2];///經過manacher處理之后的字符串 int p[MAXN*2];///保存回文串半徑,ps每個回文串長度一定為奇數int ll[MAXN*2];///第一個回文串可能的所有半徑 int rr[MAXN*2];///第三個回文串可能的所有半徑void manacher(){int i;st[0]='$';st[1]='#';for(i=1;d[i]!='\0';++i){st[i*2]=d[i];st[i*2+1]='#';}st[i*2]='\0';n=i*2-1;int MaxId=0,id;for(int i=1;i<=n;i++){if(MaxId>i)p[i]=min(p[2*id-i],MaxId-i);elsep[i]=1;while(st[i+p[i]]==st[i-p[i]])p[i]++;if(p[i]+i>MaxId){id=i;MaxId=p[i]+i;}} }int main(){int res;scanf("%d",&res);while(res--){scanf("%s",&d[1]);manacher();int l=0,r=0;for(int i=1;i<=n;i++){if(p[i]==i&&i!=1)///p[i]==i保證p[i]可以作為第一個回文串的半徑,加入ll數組,i!=1保證第一個回文串不為空ll[l++]=p[i];if(p[i]+i-1==n&&i!=n)///與上面類似rr[r++]=p[i];}int i,j;for(i=l-1;i>=0;--i){for(j=0;j<=r-1;++j){///枚舉第一個回文串和第三個回文串int tl=2*ll[i];///第二個字符串的開始位置int tr=n+1-2*rr[j];///第二個字符串的結束位置int tmp=(tl+tr)/2;///第二個字符串的中間位置,ps:這三個字符串都為奇數,可以自己想想if(tl>tr) continue;if(p[tmp]==1) continue;///第二個字符串為"#",也即是在原串中為空if(p[tmp]*2-1>=tr-tl+1)///以tmp為中點的回文串的長度大于等于第二個字符串的長度,符合題意跳出循環break;}if(j<=r-1)break;}if(i>=0)printf("Yes\n");elseprintf("No\n");}return 0; }
總結
以上是生活随笔為你收集整理的hdu 5340(manacher+枚举)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JeeWx 捷微二代微信活动平台1.0发
- 下一篇: UI标签库专题十一:JEECG智能开发平