P7114 字符串匹配(题解)
UPD : 补充一份考场代码
Description.
给定
(设
上面的最小循环节是
而此时
所以我们最终复杂度是
这个东西应该是
总复杂度
如果写棵树状数组的话应该可以
话说我在考场上甚至忘了这个怎么算,直接打了个大爆搜发现是 1e7 左右
贴一个考场 84 分代码。
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
f?x=-x:0;
}
const int N=1048585;
struct Hash
{
typedef unsigned long long ull;ull has1,has2;
inline bool operator==(Hash b) const {return has1==b.has1&&has2==b.has2;}
inline Hash operator+(Hash b) const {return(Hash){has1+b.has1,has2+b.has2};}
inline Hash operator-(Hash b) const {return(Hash){has1-b.has1,has2-b.has2};}
inline Hash operator*(Hash b) const {return(Hash){has1*b.has1,has2*b.has2};}
inline Hash operator*(ull x) const {return(Hash){has1*x,has2*x};}
inline Hash operator+(ull x) const {return(Hash){has1+x,has2+x};}
}B={149ull,1145141ull},has[N],bas[N];int qwq[1005],qaq[1005],qwqt=0;
int Q,n,pc,p[N],ls[N],st[N],tp,f[N][26];char v[N],a[N];
inline void AllInit()
{
v[0]=v[1]=1,ls[1]=1;
for(int i=2;i<N;i++)
{
if(!v[i]) p[++pc]=i,ls[i]=i;
for(int j=1;j<=pc&&p[j]*i<N;j++) {v[i*p[j]]=1,ls[i*p[j]]=p[j];if(i%p[j]==0) break;}
}
}
inline Hash geths(int l,int r) {return has[r]-bas[r-l+1]*has[l-1];}
inline int getmn(int l,int r)//最小循环节
{
int len=r-l+1;tp=0;
while(len!=1) st[++tp]=ls[len],len/=ls[len];
len=r-l+1;for(int i=1;i<=tp;i++)
{
int nxt=len/st[i];
if(geths(l,r-nxt)==geths(l+nxt,r)) len=nxt;
}
return len;
}
inline void InitHash()
{
bas[0]=(Hash){1ull,1ull},has[0]=(Hash){0ull,0ull};
for(int i=1;i<=n;i++) bas[i]=bas[i-1]*B,has[i]=has[i-1]*B+a[i];
}
inline void InitF()
{
int now=0,bit=0;memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
if(bit&(1<<(a[i]-'a'))) now--;else now++;
bit^=(1<<(a[i]-'a')),f[i][now]=1;
}
for(int i=1,j=0;i<=n;i++) f[i][j]+=f[i-1][j];
for(int i=1;i<=n;i++) for(int j=1;j<26;j++) f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
}
inline void ChaiFen(int now,int ggg,long long &x,int hzlim,int tims)
{
if(now==qwqt+1) return(void)(x+=f[tims*ggg-1][hzlim]);//,printf("F %d %d\n",tims*ggg-1,hzlim)
for(int i=0;i<=qaq[now];i++) ChaiFen(now+1,ggg,x,hzlim,tims),ggg*=qwq[now];
}
inline void solve()
{
scanf("%s",a+1),n=strlen(a+1),InitHash(),InitF();
int bit=0,now=0;long long res=0;
for(int i=n;i>2;i--)
{
if(bit&(1<<(a[i]-'a'))) now--;else now++;
bit^=(1<<(a[i]-'a'));int nown=i-1,nowlen=getmn(1,nown);
tp=0;int bf=nown/nowlen;
while(bf!=1) st[++tp]=ls[bf],bf/=ls[bf];
sort(st+1,st+tp+1),qwqt=0;
for(int j=1;j<=tp;j++) if(st[j]!=st[j-1]) qwq[++qwqt]=st[j],qaq[qwqt]=1;else qaq[qwqt]++;
// for(int j=1;j<=qwqt;j++) printf("<%d,%d>%c",qwq[j],qaq[j],j==qwqt?'\n':' ');
ChaiFen(1,1,res,now,nowlen);
// printf("%d : %lld\n",i,res);
}
printf("%lld\n",res);
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
AllInit();
for(read(Q);Q--;) solve();
fclose(stdin);
fclose(stdout);
return 0;
}
Solution2(84pts?
首先,这个出现次数为奇数这个条件很烦人,所以我们观察一下它有没有特殊性质。
首先,我们思考一下,一个串
所以,我们发现
那么我们可以奇偶分开讨论,把上面的那个
复杂度
Solution3(100pts?
鸣谢神仙
首先我们暴力枚举
然后对于每个长度,我们二分它
因为长度越长这个字符串越不可能循环,所以具有单调性。
上面的东西是
据神仙
我们获得了每个
同时,当
然后枚举
复杂度均摊
upd:
感谢 神仙
upd:
艹,神仙
完结撒花,反正笔者只会 solution1,还不知道有没有打挂