zoukankan      html  css  js  c++  java
  • P4709 信息传递 解题报告

    P4709 信息传递 解题报告:

    更好的阅读体验

    题意

    给定置换 \(f\),求有多少个置换 \(g\) 满足 \(g^n=f\)

    \(1\leqslant |f|\leqslant 10^5\)

    分析

    首先这种题一看到就把置换拆分成若干个循环置换。

    对于一个循环置换 \(g\),我们考虑它的 \(n\) 次方的形态:应该是 \(\gcd(|g|,n)\) 个相同的循环,那么等价地,\(a\) 个大小为 \(b\) 的循环能够拼起来当且仅当 \(\gcd(ab,n)=a\)

    由于我们得到的是最终的循环置换,所以我们考虑把若干个大小相同的循环拼起来,我们仅需要对于每个环大小计算其贡献然后乘起来就好了。

    我们考虑 \(a\) 个大小为 \(b\) 的环拼起来有多少种方法,由于是环首先要钦定一个位置作为开始,不妨令其为第一个环的第一个位置,而由于其他环需要断环为链,且内部要进行排列,所以一共会有 \((a-1)!b^{a-1}\) 种方案。

    我们设一共有 \(k\) 个大小为 \(b\) 的环,设 \(f_i\) 表示用了 \(k\) 个环的代价,可以列出转移方程:

    \[f_i\leftarrow\sum_{d=1}^i[\gcd(b\times d,n)=d](d-1)!b^{d-1}{i-1\choose d-1}f_{i-r} \]

    注意这里是 \({i-1\choose d-1}\) 是因为若干次选择之间是无序的,所以我们需要钦定一个环为第一个选的才能去重。

    枚举 \(d\) 可以只枚举 \(n\) 的因子,最终复杂度为 \(O(nd(n)+\sqrt{n}d(n)\log n)\)

    代码

    目前是最优解 rk1。

    #include<stdio.h>
    #include<vector>
    using namespace std;
    const int maxn=100005,mod=998244353;
    int n,ans;
    int p[maxn],vis[maxn],tot[maxn],f[maxn],fac[maxn],inv[maxn],nfac[maxn],mul[maxn];
    vector<int>v,d;
    int gcd(int a,int b){
    	return b==0? a:gcd(b,a%b);
    }
    int solve(int a,int b){
    	f[0]=mul[0]=1;
    	for(int i=1;i<=a;i++)
    		mul[i]=1ll*mul[i-1]*b%mod;
    	d.clear();
    	for(int i=0;i<v.size()&&v[i]<=a;i++)
    		if(gcd(b*v[i],n)==v[i])
    			d.push_back(v[i]);
    	for(int i=1;i<=a;i++){
    		f[i]=0;
    		for(int j=0;j<d.size()&&d[j]<=i;j++)
    			f[i]=(f[i]+1ll*mul[d[j]-1]*f[i-d[j]])%mod;
    		f[i]=1ll*f[i]*inv[i]%mod;
    	}
    	return 1ll*f[a]*fac[a]%mod;
    }
    int main(){
    	scanf("%d",&n);
    	fac[0]=nfac[0]=1;
    	for(int i=1;i<=n;i++)
    		fac[i]=1ll*fac[i-1]*i%mod,inv[i]=i==1? 1:(mod-1ll*(mod/i)*inv[mod%i]%mod),nfac[i]=1ll*nfac[i-1]*inv[i]%mod;
    	for(int i=1;i<=n;i++)
    		scanf("%d",&p[i]);
    	for(int i=1;i<=n;i++)
    		if(vis[i]==0){
    			int cnt=0;
    			for(int j=i;vis[j]==0;j=p[j])
    				vis[j]=1,cnt++;
    			tot[cnt]++;
    		}
    	for(int i=1;i<=n;i++)
    		if(n%i==0)
    			v.push_back(i);
    	ans=1;
    	for(int i=1;i<=n;i++)
    		if(tot[i])
    			ans=1ll*ans*solve(tot[i],i)%mod;
    	printf("%d\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    JSON的序列化和反序列化
    XML的序列化和反序列化
    FTP相关操作
    滑动换屏——Fragment
    AngularJS中复选框(checkbox)的ng-model
    AngularJS将时间戳格式化处理
    Let definitions are not supported by current JavaScript version
    MyBatis中的 suffixOverrides="," 失效
    MyBatisSystemException: Malformed OGNL expression: status != null
    MySQL字符串截取
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/15715415.html
Copyright © 2011-2022 走看看