C - Cornelia Street
题目链接:C - Cornelia Street
题意:给出一个字符串S,要求找出两个子串A和B,A和B等长,S可以表示成

其中a是A的前缀,a的长度大于等于0并且小于A的长度
思路:利用字符串哈希,寻找一个A,一个B,和一个A不断匹配是否出现过,这里用一个数组存下了hash值,然后比较当前字符串和后面是否有相等的字符串,有则是A,当A匹配成功时,中间那部分就是B
字符串hash,13331是经验值,这个素数统计规律得到,冲突概率小。
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> using namespace std; typedef unsigned long long ull; const int N=8e5+10; const int P=13331; char str[N]; ull h[N],p[N];//h[k]存储字符串前k个字母的哈希值,p[k]存储 p^k mod 2^64 /***********************字符串板子*************************/ void init() { p[0]=1; for(int i=1; i<=N; i++) { h[i]=h[i-1]*P+str[i]; p[i]=p[i-1]*P; } } ull get_hash(int l,int r) { return h[r]-h[l-1]*p[r-l+1]; } /***********************字符串板子*************************/ int main() { int t; cin>>t; while(t--) { scanf("%s",str+1); int n=strlen(str+1); init(); for(int i=1; i<=n/3; i++) { ull c[]= {0,get_hash(1,i),0,0,0}; int now=1;//用来表示数组下标的变量 int posb;//用来存储B字符串的起始下标 for(int j=1; j<=n-i+1; j+=i) { ull temp=get_hash(j,j+i-1); if(temp!=c[now]) { //cout<<"now"<<now<<endl; c[++now]=temp;//存A,存B,再存A if(now==2) posb=j;//有两个一样的就保存字符串hash值 } if(now>3) break;//剪枝,三个以上的都不用保存,没用 } if(now==3&&c[1]==c[3])//1位置和3位置保存了需要相等的两个值 { int l=n%i; if(get_hash(1,l)==get_hash(n-l+1,n)) //get_hash(1,l)A的hash值, get_hash(n-l+1,n)匹配串的hash值 { for(int j=1; j<=i; j++) putchar(str[j]); putchar(' '); for(int j=posb; j<=posb+i-1; j++) putchar(str[j]); putchar('\n'); } break; } } } return 0; }

浙公网安备 33010602011771号