hdu5304
2015-08-03 17:21
351 查看
BC的题出的真的太木有层次了。。让我这种渣渣怎么活。。不知道以后有dv1,dv2后会不会有所改善。。
首先,要求出所有的回文子串,因为子串长度最大为20w,所以我们得用接近线性的方法来求才行。此时,Manacher算法就派上了用场。它能以O(n)的效率求出以每个字符为中心的最长回文子串的长度。
Manacher具体的思想还是不难懂的,只要好好参悟下,给个链接:http://blog.sina.com.cn/s/blog_70811e1a01014esn.html
对于此题,我们先用Manacher方法求出所有p[i],然后遍历这个数组,找出所有包含前缀和后缀的最长子串位置。
对于所有前缀和后缀的位置,如果前缀所涉及到最长子串位置与后缀的最长子串位置有重合,那么不符合条件。否则就判断它们中间位置的最长子串长度是否大于等于中间子串的长度即可。
首先,要求出所有的回文子串,因为子串长度最大为20w,所以我们得用接近线性的方法来求才行。此时,Manacher算法就派上了用场。它能以O(n)的效率求出以每个字符为中心的最长回文子串的长度。
Manacher具体的思想还是不难懂的,只要好好参悟下,给个链接:http://blog.sina.com.cn/s/blog_70811e1a01014esn.html
对于此题,我们先用Manacher方法求出所有p[i],然后遍历这个数组,找出所有包含前缀和后缀的最长子串位置。
对于所有前缀和后缀的位置,如果前缀所涉及到最长子串位置与后缀的最长子串位置有重合,那么不符合条件。否则就判断它们中间位置的最长子串长度是否大于等于中间子串的长度即可。
#include<stdio.h> #include<iostream> #include<string> #include<string.h> #include<algorithm> #include<iomanip> #include<vector> #include<time.h> #include<queue> #include<stack> #include<iterator> #include<math.h> #include<stdlib.h> #include<map> #include<set> #include<limits.h> //#define ONLINE_JUDGE #define eps 1e-8 #define INF 0x7fffffff #define FOR(i,a) for((i)=0;i<(a);(i)++) #define MEM(a) (memset((a),0,sizeof(a))) #define sfs(a) scanf("%s",a) #define sf(a) scanf("%d",&a) #define sfI(a) scanf("%I64d",&a); #define pf(a) printf("%d\n",a) #define pfI(a) printf("%I64d\n",a) #define pfs(a) printf("%s\n",a) #define sfd(a,b) scanf("%d%d",&a,&b) #define sft(a,b,c)scanf("%d%d%d",&a,&b,&c) #define for1(i,a,b) for(int i=(a);i<b;i++) #define for2(i,a,b) for(int i=(a);i<=b;i++) #define for3(i,a,b)for(int i=(b);i>=a;i--) #define MEM1(a) memset(a,0,sizeof(a)) #define MEM2(a) memset(a,-1,sizeof(a)) const double PI = acos(-1.0); template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; } template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; } template<class T> inline T Min(T a, T b) { return a < b ? a : b; } template<class T> inline T Max(T a, T b) { return a > b ? a : b; } #define ll long long using namespace std; int n,m; #define M 1000010 #define N 110050 char ch ; char s ; int tot; int p ; void Manacher(){ memset(p,0,sizeof p); for(int i=1,j=0,k;i<tot;){ while(i-j-1>=0 && i+j+1<tot && s[i-j-1] == s[i+j+1]) j++; p[i] = j; for(k=1;k<=j && i-k>=0 && p[i]-k!=p[i-k];k++) p[i+k] = Min(p[i-k],p[i]-k); i += k; j = Max(j-k,0); } vector<int> top; vector<int> tail; for(int i=1;i<tot-1;i++){ if(i-p[i] == 0) top.push_back(i); //记录所有包含前缀的位置 if(i+p[i] == tot-1) tail.push_back(i); //记录所有包含后缀的位置 } int size1 = (int)top.size(); int size2 = (int)tail.size(); int flag = 0; for(int i=0;i<size1;i++){ for(int j=0;j<size2;j++){ int s1 = top[i]+p[top[i]]+1; //中间子串的起始位置 int s2 = tail[j]-p[tail[j]]-1;//中间子串的终止位置 if(s1>s2) continue; //如果有相交,则不符合条件 int mid = (s1+s2)/2; //否则计算中间子串的中间位置 if(p[mid]>=mid-s1) //p[mid]为中间位置的最长回文子串半径,mid-s1为中间子串的半径,如果前者大于后者 //则说明中间的这个子串也是一个回文子串,至此,该字符串被分割成为了三个回文子串 flag=1; if(flag) break; } if(flag) break; } if(flag) printf("Yes\n"); else printf("No\n"); } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif int t; sf(t); while(t--){ sfs(ch); int len = strlen(ch); tot=0; s[tot++] = '#'; for(int i=0;i<len;i++){ s[tot++] = ch[i]; s[tot++] = '#'; } Manacher(); // for(int i=0;i<tot;i++) // printf("%d ",p[i]); // puts(""); } return 0; }
相关文章推荐
- 异步委托
- 给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号","隔开。
- GBDT(MART) 迭代决策树入门教程 | 简介
- 读《招聘一个靠谱的 iOS》前序
- java 学习笔记------画图函数的认识
- 用Jquery实现可编辑表格并用AJAX提交到服务器修改数据
- 利用symbollicatecrash工具查看crash文件
- python操作Excel读写--使用xlrd
- spring入门基础(一)
- 在SDK中使用GDI+出现的编译问题解决方法
- VS2008+Qt4.7.3+VTK5.10.1+PCL1.5.1
- 边框属性border
- [LeetCode]#11 Container With Most Water
- Hbuilder主页面控制子页面的方法
- 第五篇T语言实例开发,百变字符(版本5.0)
- 修改myeclipse的jsp模板
- 线程属性设置
- IOS本地化操作
- Visual C++ 2008进行MySQL编程
- 1-4 传统操作系统的分类