51Nod 1317 相似字符串对
分析:
考虑两个串的关系:$A+C=C+B$,我们观察可以发现,$A$和$B$是循环同构的,如果$A=G+H$,那么$B=H+G$,证明略长懒得写了...
我们知道$A$串有$K^N$种,所以,我们只需要考虑对于所有的$A$串,有多少个$B$串可以和它构成合法的字符串对...如果我们不考虑重复的情况,有$N$种划分$A$串的方法...
但是有重复的情况,考虑如何去重...
我们假设$G$的长度为$p$和$q(p<q)$的时候$B$相等...那么有有以下的性质:
$B: A[p]A[p+1]A[p+2]......A[n-1]A[0]A[1]...A[p-1]$
$B: A[q]A[q+1]A[q+2]....A[n-1]A[0]A[1].....A[q-1]$
我们定义$L$代表$q-p$
那么对于任意的$A[i]$,都有$A[i]=A[(i+L)%n]$,诶,这就是循环节啊...也就是说,当$A$的最小循环节长度为$x$的时候,$A$串对应的$B$串有$x$个...
所以,我们记$f[p]$代表长度为$p$的并且最小循环节就是它本身的字符串的合法方案...那么$ans=\sum _{p\mid n} p*f[p]$,至于$f[p]$的求法就是容斥啦...用总的方案数减去所有不和发的方案数,也就是枚举循环节长度并减去...因为一个数的因子一定是它的倍数的因子,所以我们需要求出的$f$的个数只有$n$的因子个数个...
代码:
#include<algorithm> #include<cstdio> #include<cmath> const int N=50000+5,M=1e9+7; int n,m,k,a,c,f[N],d[N]; inline int p(int x,int y){ int r=1; while(y){ if(y&1)r=1LL*r*x%M; x=1LL*x*x%M,y>>=1; }return r; } signed main(void){ scanf("%d%d",&n,&k);f[1]=k;m=sqrt(n); for(int i=1;i<=m;i++)if(n%i==0){d[++c]=i;if(i*i!=n)d[++c]=n/i;} std::sort(d+1,d+c+1); for(int i=2;i<=c;i++){ f[i]=p(k,d[i]); for(int j=1;j<i;j++)if(d[i]%d[j]==0)f[i]=(f[i]-f[j]+M)%M; } for(int i=1;i<=c;i++)a=(a+1LL*d[i]*f[i]%M)%M;printf("%d\n",a); }
By NeighThorn