test20181004 排列

题意

分析

容斥公式的意义

选了原图中\(x(x \geq i)\)条边的方案,重复了\(\binom{x}{i}\)次。
有多加多减,所以就是那个式子。
具体而言,对选了x条原图中的边的方案,总共加减了

\[\sum_{i=0}^{x} \binom{x}{i} \cdot (-1)^{i}\\ = (1 + (-1))^x = 0 \]

这么多次。用二项式定理即可证明上述式子在x>0的情况下均为0。

dp方程解释

所谓选第i个点就是说选了i和i-1之间的这条边。

代码

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
#define LL ll
#define p mod
using namespace std;
template<class T> inline T read(T&x)
{
    T data=0;
	int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
		if(ch=='-')
			w=-1;
		ch=getchar();
	}
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return x=data*w;
}
using ll = long long;
constexpr int INF=0x7fffffff;

constexpr int MAXN=2007,mod=998244353;
int fac[MAXN];
int g[MAXN],f[MAXN][MAXN][2];
int up;

int main()
{
  freopen("permutation.in","r",stdin);
  freopen("permutation.out","w",stdout);
	int n,k;
	read(n);read(k);
	fac[0]=1;
	for(int i=1;i<=n;++i)
		fac[i] = (ll)fac[i-1] * i % mod;
	g[0]=1;
	for(int cs=1;cs<=2;++cs)
	{
		for(int i=1;i<=k;++i)
		{
			f[i][0][0]=1;
			int j=i,tp=0;
			for(;;)
			{
				if(j+k>n)
					break;
				j+=k,++tp;
				for(int l=0;l<=tp;++l)
				{
					f[j][l+1][1] = f[j-k][l][0];
					f[j][l][0] = (f[j-k][l][0] + f[j-k][l][1]) % mod;
				}
			}
			for(int l=up;l>=0;--l)
				for(int m=1;m<=tp;++m)
					(g[l+m] += (ll)g[l] * (f[j][m][0] + f[j][m][1]) % mod) %= mod;
			up+=tp;
		}
	}
	int ans=0;
	for(int i=0;i<=n;++i)
	{
		if(i&1)
			(ans += mod - (ll)g[i] * fac[n-i] % mod) %= mod;
		else
			(ans += (ll)g[i] * fac[n-i] % mod) %= mod;
	}
	printf("%d\n",ans);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

posted on 2018-10-04 21:25  autoint  阅读(128)  评论(0编辑  收藏  举报

导航