题意
题目描述
给定一个$n$个点,$n$条边的环,有$n$种颜色,给每个顶点染色,问有多少种本质不同的染色方案,答案对$10^9+7$取模
注意本题的本质不同,定义为:只需要不能通过旋转与别的染色方案相同。
输入输出格式
输入格式:第一行输入一个$t$,表示有$t$组数据
第二行开始,一共$t$行,每行一个整数$n$,意思如题所示。
输出格式:共$t$行,每行一个数字,表示染色方案数对$10^9+7$取模后的结果
输入输出样例
说明
$$n \leq 10^9$$ $$t \leq 10^3$$
分析
先找不动点个数公式。考虑循环移动\(i\)位这个置换,把珠子循环编号。由于移动后编号要重复,所以最大的编号一定是\(\textrm{lcm}(i,m)\)。所以一个循环里面的珠子个数就是\(\frac{\textrm{lcm}(i,m)}{i}=\frac{n}{\gcd(i,n)}\)。所以共有\(\gcd(i,n)\)个循环。因此不动点个数是\(n^{\gcd(i,n)}\)
所以答案式为
\[ \frac 1n\sum_{i=0}^{n-1}n^{\gcd(i,n)} \\ =\frac 1n\sum_{d|n}\varphi(\frac nd)n^d \\ =\sum_{d|n}\varphi(d) n^{\frac nd-1} \]
我并不知道先枚约数再算欧拉函数的复杂度是多少,反正约数个数怎么也达不到\(O(\sqrt{n})\)的上界。
即使\(2^3*3*5*7*11*13*17*19*23=892371480\),这个数也只有1024个约数,小于\(\sqrt{892371480}=29872.587433\)。
int phi(int n){ int re=n; for(int i=2;i*i<=n;++i)if(n%i==0){ re=re/i*(i-1); while(n%i==0) n/=i; } if(n>1) re=re/n*(n-1); return re; } void Polya(){ int n=read<int>(),ans=0; for(int i=1;i*i<=n;++i)if(n%i==0){ ans=add(ans,mul(phi(i),fpow(n,n/i-1))); if(i*i!=n) ans=add(ans,mul(phi(n/i),fpow(n,i-1))); } printf("%d\n",ans); } int main(){ // freopen("LG4980.in","r",stdin),freopen("LG4980.out","w",stdout); for(int t=read<int>();t--;) Polya(); return 0; }
宝石纪念币
跟上面那道题一样。不过多了些要求:共17中颜色,每种都要用上。保留120位数。
那么简单容斥,并实现高精度即可。
https://cyaron.blog.luogu.org/solution-p2162
我果然写不来高精度……算是做个高精练习吧。
不想容斥的话也可以用矩阵乘法:https://www.cnblogs.com/ccz181078/p/7122566.html?utm_source=itdadao&utm_medium=referral
CO int mod=1e9;int n; // qn+r inter node(int x){ inter a(15); a[0]=x%n,a[1]=x/n; return a; } inter operator+(CO inter&a,CO inter&b){ inter ans(15); ans[0]=a[0]+b[0]; if(ans[0]>=n) ++ans[1],ans[0]-=n; for(int i=1;i<=14;++i){ ans[i]+=a[i]+b[i]; if(ans[i]>=mod){ if(i+1<=14) ++ans[i+1]; ans[i]-=mod; } } return ans; } inter operator-(CO inter&a,CO inter&b){ // a>=b inter ans(15); ans[0]=a[0]-b[0]; if(ans[0]<0) --ans[1],ans[0]+=n; for(int i=1;i<=14;++i){ ans[i]+=a[i]-b[i]; if(ans[i]<0){ if(i+1<=14) --ans[i+1]; ans[i]+=mod; } } return ans; } inter operator*(CO inter&a,CO inter&b){ vector<int128> ans(15); ans[0]=(int128)a[0]*b[0]; ans[1]+=ans[0]/n,ans[0]%=n; for(int i=1;i<=14;++i){ ans[i]+=(int128)a[i]*b[0]+(int128)a[0]*b[i]; for(int j=1;j<=i;++j) ans[i]+=(int128)a[j]*b[i+1-j]*n; if(i+1<=14) ans[i+1]+=ans[i]/mod; ans[i]%=mod; } return inter(ans.begin(),ans.end()); } inter pow(inter a,int b){ inter ans(15);ans[0]=1; for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a; return ans; } int phi(int n){ int ans=n; for(int i=2;i*i<=n;++i)if(n%i==0){ ans=ans/i*(i-1); while(n%i==0) n/=i; } if(n>1) ans=ans/n*(n-1); return ans; } int C[20][20]; int main(){ read(n); if(n<17){ for(int i=1;i<=120;++i) putchar('0'); puts(""); return 0; } for(int i=0;i<=17;++i){ C[i][0]=C[i][i]=1; for(int j=1;j<i;++j) C[i][j]=C[i-1][j-1]+C[i-1][j]; } inter ans(15); for(int d=1;d*d<=n;++d)if(n%d==0){ inter sum(15); for(int i=1;i<=17;i+=2) sum=sum+node(C[17][i])*pow(node(i),d); for(int i=2;i<=17;i+=2) sum=sum-node(C[17][i])*pow(node(i),d); sum=sum*node(phi(n/d)); ans=ans+sum; if(n/d==d) continue; sum=node(0); for(int i=1;i<=17;i+=2) sum=sum+node(C[17][i])*pow(node(i),n/d); for(int i=2;i<=17;i+=2) sum=sum-node(C[17][i])*pow(node(i),n/d); sum=sum*node(phi(d)); ans=ans+sum; } printf("%03d",ans[14]%1000); // edit 1 for(int i=13;i>=1;--i) printf("%09d",ans[i]); puts(""); return 0; }
来源:https://www.cnblogs.com/autoint/p/10689584.html