【51nod1317】相似字母对(容斥)

点此看题面

大致题意: 求有多少对长度为(n)、字符集大小为(k)的字符串(A,B),满足(A)(B)循环同构。

容斥

一个显然的结论,对于一个字符串(A),能与它同构的(B)的个数等于(A)的循环节长度。

考虑求出(f(i))表示最小循环节长度为(i)的字符串个数,答案就是(sum f(i) imes i)

但最小这个限制显然很棘手,于是我们就用容斥,发现(f(i)=k^i-sum_{j|i}f(j))

然后,还有一个明显的性质,合法循环节长度必然是(n)的因数。

(10^9)范围内因数最多的数也只有(1344)个因数。

于是复杂度就是(O(1344^2))

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define S 1344
#define X 1000000007
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
#define Dec(x,y) ((x-=(y))<0&&(x+=X))
using namespace std;
int n,k,t,p[S+5],f[S+5];
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
	RI i;for(scanf("%d%d",&n,&k),i=1;i*i<=n;++i) !(n%i)&&(p[++t]=i,i^(n/i)&&(p[++t]=n/i));//存下因数
	RI j;for(sort(p+1,p+t+1),i=1;i<=t;++i)//枚举循环节长度
		for(f[i]=QP(k,p[i]),j=1;j^i;++j) !(p[i]%p[j])&&Dec(f[i],f[j]);//容斥
	RI ans=0;for(i=1;i<=t;++i) ans=(1LL*f[i]*p[i]+ans)%X;return printf("%d
",ans),0;//统计答案并输出
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/51nod1317.html