【CF285E】Positions in Permutations(动态规划,容斥)

【CF285E】Positions in Permutations(动态规划,容斥)

题面

CF
洛谷

题解

首先发现恰好很不好算,所以转成至少,这样子只需要确定完一部分数之后剩下随意补。
然后套一个二项式反演进行容斥就可以得到答案了。
考虑怎么算至少\(m\)个的贡献,
\(f[i][j][S]\)表示当前填到了位置\(i\),一个有\(j\)个贡献,\(i\)\(i+1\)的使用情况是\(S\)的方案数,每次枚举一下这个位置是填\(i+1\)还是\(i-1\)还是其他就可以进行转移了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
#define MAX 1010
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,m,jc[MAX],a[MAX],ans;
int f[MAX][MAX][4],C[MAX][MAX];
int main()
{
	n=read();m=read();
	jc[0]=1;for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
	for(int i=0;i<=n;++i)C[i][0]=1;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=i;++j)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
	f[0][0][1]=1;
	for(int i=1;i<=n;++i)
		for(int j=0;j<i;++j)
			for(int S=0;S<4;++S)
			{
				if(!f[i-1][j][S])continue;
				add(f[i][j][S>>1],f[i-1][j][S]);
				if(!(S&1))add(f[i][j+1][S>>1],f[i-1][j][S]);
				if(i!=n)add(f[i][j+1][(S>>1)|2],f[i-1][j][S]);
			}
	for(int i=0;i<=n;++i)
		for(int S=0;S<4;++S)
			add(a[i],1ll*f[n][i][S]*jc[n-i]%MOD);
	for(int i=m,d=1;i<=n;++i,d=MOD-d)add(ans,1ll*d*C[i][m]%MOD*a[i]%MOD);
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-05-26 15:46  小蒟蒻yyb  阅读(453)  评论(0编辑  收藏  举报