NC20371. [SDOI2015]双旋转字符串
描述
输入描述
第一行输入四个正整数,分别为 TotalS,TotalT,N 和 M,依次表示集合 S 的大小,集合 T 的大小,集合 S 中字符串的长度和集合 T 中字符串的长度。之后 TotalS 行,依次给出 S 中所有的字符串 Si,1 ≤ i ≤ TotalS。保证每一个字符串长度都恰为 N ,且字符串只由 26 个小写字母组成。之后 TotalT 行,依次给出 T 中所有的字符串 Ti,1 ≤ i ≤ TotalT。保证每一个字符串长度都恰为 M ,且字符串只由 26 个小写字母组成。1 ≤ N ≤ 100;1 ≤ M ≤ 100;1 ≤ TotalS ≤ 100;1 ≤ Total^T ≤ 100,2 ≤ N*TotalS+M*TotalT ≤ 4×10^6,N ≥ M
输出描述
输出一个整数,表示满足要求的数字对 < i,j > 有多少个。
示例1
输入:
4 4 7 3 vijosvi josvivi vijosos ijosvsv jos vij ijo jos
输出:
6
C++11(clang++ 3.9) 解法, 执行用时: 529ms, 内存消耗: 5420K, 提交时间: 2020-05-21 13:44:25
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<map> typedef long long LL; using namespace std; const int MOD=10037;//乘的东西 const int MOD1=1000000007; const int N=4000005; int S,T,n,m,o; char ss[N],s1[N]; LL shen[N];//前i为的hash值 LL KK,KKK; map<int,int> q; struct qq { int x; }s[N*2];int cnt=0; bool cmp (qq a,qq b){return a.x<b.x;} void add () { cnt=0; LL p1=0; for (int u=1;u<=n-o;u++) p1=((p1*MOD)%MOD1+ss[u+o]-'a')%MOD1; int len=0; for (int u=1;u<=o;u++) s1[++len]=ss[u]; for (int u=1;u<=o;u++) s1[++len]=ss[u]; shen[0]=0; for (int u=1;u<=len;u++) shen[u]=((shen[u-1]*MOD)%MOD1+s1[u]-'a')%MOD1; for (int u=1;u<=o;u++)//枚举开头在哪里 { LL a=((shen[u+n-o-1]-shen[u-1]*KKK%MOD1)%MOD1+MOD1)%MOD1; if (a!=p1) continue; a=((shen[u+o-1]-shen[u+n-o-1]*KK%MOD1)%MOD1+MOD1)%MOD1; s[++cnt].x=(int)a; } sort(s+1,s+1+cnt,cmp);s[0].x=-1; for (int u=1;u<=cnt;u++) if (s[u].x!=s[u-1].x) q[s[u].x]++; } int main() { scanf("%d%d%d%d",&S,&T,&n,&m);o=(n+m)>>1;//中间端点是什么 KK=1; for (int u=1;u<=2*o-n;u++) KK=KK*MOD%MOD1; KKK=1; for (int u=1;u<=n-o;u++) KKK=KKK*MOD%MOD1; for (int u=1;u<=S;u++) { scanf("%s",ss+1); add(); } int ans=0; for (int u=1;u<=T;u++) { scanf("%s",ss+1); LL p=0; for (int i=1;i<=m;i++) p=((p*MOD)%MOD1+ss[i]-'a')%MOD1; ans=ans+q[p]; } printf("%d\n",ans); return 0; }
C++14(g++5.4) 解法, 执行用时: 596ms, 内存消耗: 5844K, 提交时间: 2020-03-30 17:21:27
#include <bits/stdc++.h> #define ull unsigned long long using namespace std; const int MX=4e6+9; const int base=131; char s[MX],t[MX]; int n,m,ls,lt,mid; ull has[MX],bas[MX]; map<ull,int> mp; ull get(int l,int r){ if( l==0 ) return has[r]; else return has[r]-has[l-1]*bas[r-l+1]; } void inst(){ char s1[MX]; for( int i=0 ; i<mid ; i++ ) s1[i]=s1[i+mid]=s[i]; has[0]=s1[0]-'a'+1; for( int i=1 ; i<2*mid ; i++ ) has[i]=has[i-1]*base+s1[i]-'a'+1; int len=ls-mid; ull pos=0; for( int i=mid ; i<ls ; i++ ) pos=pos*base+s[i]-'a'+1; for( int i=0 ; i<mid ; i++ ){ ull po=get(i,i+len-1); if( po==pos ){ int l=i+len,r=l+mid-len-1; mp[get(l,r)]++; } } } int main() { // freopen("input.txt","r",stdin); scanf("%d %d %d %d",&n,&m,&ls,<); bas[0]=1; for( int i=1 ; i<=ls+lt ; i++ ) bas[i]=bas[i-1]*base; mid=(ls+lt)>>1; for( int i=1 ; i<=n ; i++ ){ scanf("%s",s); inst(); } int ans=0; for( int i=1 ; i<=m ; i++ ){ scanf("%s",t); ull pos=0; for( int i=0 ; i<lt ; i++ ) pos=pos*base+t[i]-'a'+1; if( mp.count(pos) ) ans+=mp[pos]; } printf("%d\n",ans); return 0; }