@rebirth1120
2019-08-06T17:03:58.000000Z
字数 1603
阅读 618
解题报告
各省省选
为 n 个人编排位置,不同的人的位置编号可以相同。n 个人会依次去找自己的位置,设第 个人的位置编号为 ,若 已经有人坐了,则这个人会去找 后的位置,找到一个空的位置马上坐下来,若有人无法坐下来,则这个方案是不合法的。
现有 个人,他们的位置已经确定了,求编排位置的方案数。
若没有合法的方案,则输出 NO,
否则输出 YES + 合法方案数。
对于判断是否有合法的方案数,可以先计算出每个位置已经安排的人数的后缀和 ,若 ,则不可能有合法的方案。
对于统计方案数,考虑dp。
设 为(从后往前)考虑到第 个位置,已经为 个人安排位置的方案数,转移方程为:
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using 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;
}