ABC226F x ABC180F

显然答案为 \(LCM(l_1,l_2,l_3...l_k)\),其中 \(l\) 是置换环长度。

考虑 \(DP\) 处理 \(LCM\)
image

相信大家看得懂英文。这里只解释一下 \(\dbinom{n-i-1}{x-1}\)。意义是先选一个固定的起点,这个起点编号最小,再选剩下的点。 为什么要起点编号最小?试想一下,我们选多次时,假设有四个点,不固定起点,每次选两个:
image

这个图有点鬼畜。。。蓝色表示第一次选的,红色为第二次选的。另一种情况是:

image

这难道是传说中的小红帽?但实际上这两种情况是一样的。于是我们必须强制性的每轮先选编号最小的。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50,P=998244353;
map<ll,ll> dp[N+5];
int n,k,fac[N+5],inv[N+5],ans;
int KSM(int a,int b)
{
	int ret=1;
	while(b)
	{
		if(b&1) ret=1ll*ret*a%P;
		a=1ll*a*a%P;b>>=1;
	}
	return ret;
}
int C(int a,int b) {return 1ll*fac[a]*inv[b]%P*inv[a-b]%P;}
int lcm(int a,int b){return a/__gcd(a,b)*b;}
int main()
{
	fac[0]=inv[0]=1;for(int i=1; i<=N; i++) fac[i]=1ll*fac[i-1]*i%P;
	inv[N]=KSM(fac[N],P-2);
	for(int i=N-1; i>=1; i--) inv[i]=1ll*(i+1)*inv[i+1]%P;
	cin>>n>>k;
	dp[0][1]=1;
	for(int i=0; i<n; i++)
		for(int j=1; i+j<=n; j++)
			for(auto p:dp[i])
				dp[i+j][lcm(p.first,j)]+=p.second*fac[j-1]%P*C(n-i-1,j-1)%P,
				dp[i+j][lcm(p.first,j)]%=P;
	for(auto p:dp[n]) ans=(ans+1ll*p.second*KSM(p.first,k)%P)%P;cout<<ans;
	return 0;
}

这题只是顺带一提,因为也用到了这个结论。

题解就自己看吧。。也是用 \(DP\)

code

#include<bits/stdc++.h>
using namespace std;
const int N=300,P=1e9+7,inv2=(P+1)/2;
int n,m,L,fac[N+5],inv[N+5];
int dp[N+5][N+5];
int KSM(int a,int b)
{
	int ret=1;
	while(b)
	{
		if(b&1) ret=1ll*ret*a%P;
		a=1ll*a*a%P;b>>=1;
	}
	return ret;
}
int C(int a,int b) {return 1ll*fac[a]*inv[b]%P*inv[a-b]%P;}
void upd(int &x,int y) {x=(x+y%P)%P;x=(x+P)%P;}
int solve(int lim)
{
	memset(dp,0,sizeof dp);
	dp[0][0]=1;
	for(int i=0; i<=n; i++)
		for(int j=0; j<=m; j++)
		{
			if(lim>0&&i+1<=n) upd(dp[i+1][j],dp[i][j]);
			if(lim>1&&i+2<=n&&j+2<=m) upd(dp[i+2][j+2],1ll*dp[i][j]*(n-i-1)%P);
			for(int k=2; k<=min(lim,n); k++)
			{
				if(i+k<=n&&j+k-1<=m) upd(dp[i+k][j+k-1],1ll*dp[i][j]*C(n-i-1,k-1)%P*fac[k]%P*inv2%P);
				if(i+k<=n&&j+k<=m&&k>2) upd(dp[i+k][j+k],1ll*dp[i][j]*C(n-i-1,k-1)%P*fac[k-1]%P*inv2%P);
			}
		}
	return dp[n][m];
}
int main()
{
	fac[0]=inv[0]=1;for(int i=1; i<=N; i++) fac[i]=1ll*fac[i-1]*i%P;
	inv[N]=KSM(fac[N],P-2);
	for(int i=N-1; i>=1; i--) inv[i]=1ll*(i+1)*inv[i+1]%P;
	scanf("%d%d%d",&n,&m,&L);
	printf("%d",(solve(L)-solve(L-1)+P)%P);
	return 0;
}

The End.

posted @ 2021-11-09 10:40  keepcoder  阅读(94)  评论(0编辑  收藏  举报