把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

点此看题面

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

容斥

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

考虑求出\(f(i)\)表示最小循环节长度为\(i\)的字符串个数,答案就是\(\sum f(i)\times 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\n",ans),0;//统计答案并输出
}
posted @ 2020-08-20 09:17  TheLostWeak  阅读(130)  评论(0编辑  收藏  举报