@rebirth1120
2019-08-06T09:03:58.000000Z
字数 1603
阅读 839
解题报告 各省省选
为 n 个人编排位置,不同的人的位置编号可以相同。n 个人会依次去找自己的位置,设第 个人的位置编号为 ,若 已经有人坐了,则这个人会去找 后的位置,找到一个空的位置马上坐下来,若有人无法坐下来,则这个方案是不合法的。
现有 个人,他们的位置已经确定了,求编排位置的方案数。
若没有合法的方案,则输出 NO,
否则输出 YES + 合法方案数。
对于判断是否有合法的方案数,可以先计算出每个位置已经安排的人数的后缀和 ,若 ,则不可能有合法的方案。
对于统计方案数,考虑dp。
设 为(从后往前)考虑到第 个位置,已经为 个人安排位置的方案数,转移方程为:
#include<iostream>#include<cstring>#include<cstdio>#define ll long longusing namespace std;const int N=300+7;int T,n,m,bur[N],lim[N];ll mod,f[N][N],c[N][N];void init(){c[0][0]=c[1][0]=c[1][1]=1;for(int i=2;i<=n;i++)for(int j=0;j<=i;j++)c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;}int main(){//freopen("pc.in","r",stdin);cin>>T;while(T--){memset(f,0,sizeof(f));memset(bur,0,sizeof(bur));memset(c,0,sizeof(c));scanf("%d%d%lld",&n,&m,&mod);init();int x,q;for(int i=1;i<=m;i++){scanf("%d%d",&x,&q);bur[q]++;}int res=0; bool flag=0;for(int i=n;i>=1;i--){res+=bur[i];if(res>n-i+1){printf("NO\n");flag=1;break;}}if(flag) continue;f[n+1][0]=1;for(int i=n;i>=1;i--){lim[i]=n-i+1;for(int j=bur[i+1]+bur[i];j<=lim[i];j++)for(int k=bur[i+1];k<=min(j-bur[i],lim[i+1]);k++)f[i][j]=(f[i][j]+f[i+1][k]*c[n-k-m][j-k-bur[i]]%mod)%mod;m-=bur[i];}printf("YES %lld\n",f[1][n]);}return 0;}
