hdu5304
来源:互联网 发布:小区宽带计费软件 编辑:程序博客网 时间:2024/04/29 15:30
BC的题出的真的太木有层次了。。让我这种渣渣怎么活。。不知道以后有dv1,dv2后会不会有所改善。。
首先,要求出所有的回文子串,因为子串长度最大为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 longusing namespace std;int n,m;#define M 1000010#define N 110050char ch[N];char s[N];int tot;int p[N];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;}
0 0
- hdu5304
- 【hdu5304】生成树计数—基尔霍夫矩阵 DP
- hdu5304 Eastest Magical Day Seep Group's Summer 状压dp+生成树
- 我的第一个Java程序 helloword
- 排序算法
- BUPT Summer Training #7 for Grade 14 题解
- notes
- 未能创建SSL/TLS安全通道,导致的通过HTTPS协议访问WCF服务
- hdu5304
- Eclipse注解模板设置
- Halcon学习笔记_01:Threshold
- java.lang.UnsatisfiedLinkError:Could not load bd_wsp_v1_0 loader dalvik.system
- android自定义控件(一) 官方文档的翻译
- 自定义 Spring Security 4 的UserDetailsService和UserDetails
- HNUC-2330 Casino-算法Manacher最长回文子串
- Min Stack
- ios DDlog日志