【CF285E】Positions in Permutations(動態規劃,容斥)

【CF285E】Positions in Permutations(動態規劃,容斥)

題面

CF
洛谷ios

題解

首先發現剛好很很差算,因此轉成至少,這樣子只須要肯定完一部分數以後剩下隨意補。
而後套一個二項式反演進行容斥就能夠獲得答案了。
考慮怎麼算至少\(m\)個的貢獻,
\(f[i][j][S]\)表示當前填到了位置\(i\),一個有\(j\)個貢獻,\(i\)\(i+1\)的使用狀況是\(S\)的方案數,每次枚舉一下這個位置是填\(i+1\)仍是\(i-1\)仍是其餘就能夠進行轉移了。spa

#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;
}
相關文章
相關標籤/搜索