BZOJ 4085:[Sdoi2015]bigyration(SDOI 2015 round 2 Day 1)

时间:2023-03-09 08:19:01
BZOJ 4085:[Sdoi2015]bigyration(SDOI 2015 round 2 Day 1)

别人家的神选系列。Day2根本不能做QAQ

题目描述:给定两个字符串集合,一个长度为n,另一个为m,求有多少个数字对i,j,满足xi+yj能由一个(n+m)/2的字符串旋转拼接而成

我们枚举长度较长的集合,那么我们的那个(n+m)/2的字符串就能确定了,接下来我们就可以对y的字符串hash掉然后枚举断点就能o(1)判断啦

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define p 17
#define maxn 8000010
typedef unsigned int uint;
map<uint,int> hash,used;
uint pow[maxn],c[maxn];
string a[maxn],b[maxn];
char ch[maxn];
inline uint get(int l,int r){return c[r]-c[l-]*pow[r-l+];}
int main(){
int s,t,n,m;
scanf("%d%d%d%d",&s,&t,&n,&m);
int l=(n+m)>>;
for (int i=;i<=s;i++) {scanf("%s",ch);a[i]=string(ch);}
for (int i=;i<=t;i++) {scanf("%s",ch);b[i]=string(ch);}
if (n<m) {
for (int i=;i<=max(s,t);i++) swap(a[i],b[i]);
swap(s,t);
swap(n,m);
}
for (int i=;i<=t;i++) {
uint h=;
for (int j=;j<m;j++) h=h*p+b[i][j]-'a';
hash[h]++;
}
int ans=;
pow[]=c[]=;
for (int i=;i<=n+m;i++) pow[i]=pow[i-]*p;
for (int i=;i<=s;i++) {
used.clear();
for (int j=;j<n;j++) c[j+]=c[j]*p+a[i][j]-'a';
for (int j=;j<=l;j++) {
uint h=get(j,l)*pow[j-]+get(,j-);
if (used[h]) continue;
used[h]=;
ans+=hash[h-get(l+,n)*pow[m]];
}
}
printf("%d\n",ans);
return ;
}