zoukankan      html  css  js  c++  java
  • 6545. 【GDOI2020模拟4.8】 Exercise

    题目

    对于一个([1,n])的置换,从初始状态进行若干次直到回归初始状态的步数为它的贡献。
    求所有(n!)个置换的贡献的乘积。


    思考历程

    显然题目可以这样转化:将(n)个点分成若干个环,求环的(LCM),每种方案的成绩。
    感觉跟前些天的某道题有点像,盲猜正解是跟之前一样的优美的状压DP。
    然而之前那题本来就没有切……
    没有想出太多的东西,直接暴力DP,用map优化。
    比预估的分数高了一点点。


    正解

    考虑将每个质数(p)分开计算。
    考虑计算(p^k)的贡献。由于恰好是(p^k)不好算,所以计算至少是(p^k)。设(f(x))表示出现了(x)的倍数的方案数。
    那么(p^k)的贡献可以摊到(p^1,p^2,...,p^k)上,所以在每个小于等于(k)的指数处统计一次。于是答案为(prod p^{f(p^k)})
    现在的问题是如何计算(f(x))。枚举有多少长度为(x)的环,其它的点任意选,求出方案数之后容斥一下。
    (g(i))为确定了(ix)个点(这些点所在的环都是(x)的倍数)的方案数。
    转移的时候,枚举最小编号的点所在的环的大小,就可以做到没有重复和遗漏。
    (g(i)=-sum_{j=1}^{i}g(i-j)C(ix-1,jx-1)(jx-1)!)
    前面的负号是把容斥系数算进去了。
    (f(x)=sum_{i=1}^{frac{n}{x}}g(i)C(n,ix)(n-ix)!)
    计算一个(p)的时间复杂度是(O((frac{n}{p})^2)),由于(sum frac{1}{i^2})(O(1))的,所以总的时间复杂度为(O(n^2))
    这题还有个生成函数的做法。当然我听不懂……


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 7510
    #define ll long long
    int n,mo,mo1;
    int fac[N],C[N][N];
    bool inp[N];
    int g[N];
    inline ll qpow(ll x,int y,int m=mo){
    	ll res=1;
    	for (;y;x=x*x%m,y>>=1)
    		if (y&1)
    			res=res*x%m;
    	return res;
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    	freopen("exercise.in","r",stdin);
    	freopen("exercise.out","w",stdout);
    	scanf("%d%d",&n,&mo),mo1=mo-1;
    	fac[0]=1;
    	for (int i=1;i<=n;++i)
    		fac[i]=(ll)fac[i-1]*i%mo1;
    	for (int i=0;i<=n;++i){
    		C[i][0]=1;
    		for (int j=1;j<=i;++j)
    			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo1;
    	}
    	ll ans=1;
    	for (int p=2;p<=n;++p){
    		if (inp[p])
    			continue;
    		for (int i=p+p;i<=n;i+=p)
    			inp[i]=1;
    		for (int k=1,x=p;x<=n;++k,x*=p){
    			g[0]=mo1-1;
    			for (int i=1;i*x<=n;++i){
    				ll s=0;
    				for (int j=1;j<=i;++j)
    					s+=(ll)g[i-j]*C[i*x-1][j*x-1]%mo1*fac[j*x-1]%mo1;
    				s=(mo1-s%mo1)%mo1;
    				g[i]=s;
    			}
    			ll f=0;
    			for (int i=1;i*x<=n;++i)
    				f+=(ll)g[i]*C[n][i*x]%mo1*fac[n-i*x]%mo1;
    			f%=mo1;
    //			printf("%d %lld
    ",p,f);
    			ans=ans*qpow(p,f)%mo;
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    总结

    1. 不要什么时候都要想着可以状压……
    2. 拆成质因数算,这是个常见的套路。
    3. 善用容斥,善用“恰好”和“至少”之间的转化。
  • 相关阅读:
    Win10 主题 美化 动漫
    Win10 主题 美化 动漫
    span 居中
    This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery
    10 Future Web Trends 十大未来互联网趋势
    10 Future Web Trends 十大未来互联网趋势
    使用pycharm进行简单的数据库管理
    使用pycharm进行简单的数据库管理
    Python开发利器PyCharm 2.7附注册码
    Python开发利器PyCharm 2.7附注册码
  • 原文地址:https://www.cnblogs.com/jz-597/p/12676347.html
Copyright © 2011-2022 走看看