BZOJ 2302 HAOI2011 Problem c 动态规划

来源:互联网 发布:手绘头像软件 编辑:程序博客网 时间:2024/05/17 19:21

题目大意:给定n个人和n个位置,要求生成一个序列ai,然后第1...n个人依次走到第a1...n个位置,如果那个位置已经有人了就走到下一个位置,直到找到一个空位,坐下。如果找完第n个座位还是没有找到就称这个序列不合法
现在已经确定了一些ai,求合法序列的数量

一个序列合法等价于编号i的人至少有i
然后就可以DP辣。。。
fi,j表示编号i的人有j个的方案数,cnti表示确定编号为i的人的个数,sumi表示编号可以i的人的个数
那么有
fi,j=ji+1k=cntifi1,jkCkcntisumicnti(jk)
那个组合数表示现在有sumi个人,cnti个人已经确定必须选,jk个人已经选完了,在剩下的人中选出kcnti个人使其编号为i
时间复杂度O(Tn3)
少打个回车调了一晚上……我真是老了啊……

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 330using namespace std;int n,m,p;int cnt[M],sum[M];long long C[M][M],f[M][M];void Initialize(){    int i,j;    memset(cnt,0,sizeof cnt);    memset(C,0,sizeof C);    memset(f,0,sizeof f);    for(i=0;i<=n;i++)        for(C[i][0]=1,j=1;j<=i;j++)            C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;}int main(){    int T,i,j,k,x;    for(cin>>T;T;T--)    {        cin>>n>>m>>p;        sum[0]=n-m;        Initialize();        for(i=1;i<=m;i++)            scanf("%*d%d",&x),cnt[x]++;        for(i=1;i<=n;i++)        {            sum[i]=sum[i-1]+cnt[i];            if(sum[i]<i)            {                puts("NO");                break;            }        }        if(i!=n+1) continue;        f[0][0]=1;        for(i=1;i<=n;i++)            for(j=sum[i];j>=i;j--)                for(k=j-i+1;k>=cnt[i];k--)                    (f[i][j]+=f[i-1][j-k]*C[sum[i]-j+k-cnt[i]][k-cnt[i]])%=p;        printf("YES %d\n",(int)f[n][n]);    }    return 0;}
1 0
原创粉丝点击