数学考试【dp】

题意

(1 sim n) 的排列,有 (m) 个限制条件,第 (i) 个限制条件 (p_i) 表示前 (p_i) 个数不能是 (1sim p_i) 的排列,求符合要求的排列的个数。答案对 (20000311) 取模。

链接:https://ac.nowcoder.com/acm/contest/7745/C

(nleq 2000, m,p_i<n)

分析

首先定于状态:(dp[i]) 表示处理到第 (p_i) 个数时,前 (i-1) 个条件满足而第 (i) 个条件不满足的方案数。这个状态定义很重要,方便后面去重。

那么答案就是:

[ans=n!-sum_{i=1}^{m}{dp[i] imes (n-p[i])!} ]

显然,(dp[1]=fac[p[1]])(dp[2]=fac[p[2]]-dp[1]*fac[p[2]-p[1]]),其它的以此类推。

代码

#include <bits/stdc++.h>

using namespace std;
const int mod=20000311;
const int N=2010;
int dp[N],fac[N],p[N];
void init()
{
    int maxn=2000;
    fac[0]=1;
    for(int i=1;i<=maxn;i++)
        fac[i]=1LL*fac[i-1]*i%mod;
}
int main()
{
    init();
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d",&p[i]);
    sort(p+1,p+1+m);
    dp[1]=fac[p[1]];
    for(int i=2;i<=m;i++)
    {
        dp[i]=fac[p[i]];
        for(int j=1;j<i;j++)
            dp[i]=(dp[i]-1LL*dp[j]*fac[p[i]-p[j]]%mod+mod)%mod;
    }
    int ans=fac[n];
    for(int i=1;i<=m;i++)
        ans=(ans-1LL*dp[i]*fac[n-p[i]]%mod+mod)%mod;
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/1024-xzx/p/13838562.html