日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

hdu 5340(manacher+枚举)

發布時間:2025/3/16 编程问答 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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+枚举)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。