2302: [HAOI2011]Problem c
Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 645 Solved: 352
[ Submit][ Status][ Discuss]
Description
给n个人安排座位,先给每个人一个1~n的编号,设第i个人的编号为ai(不同人的编号可以相同),接着从第一个人开始,大家依次入座,第i个人来了以后尝试坐到ai,如果ai被占据了,就尝试ai+1,ai+1也被占据了的话就尝试ai+2,……,如果一直尝试到第n个都不行,该安排方案就不合法。然而有m个人的编号已经确定(他们或许贿赂了你的上司...),你只能安排剩下的人的编号,求有多少种合法的安排方案。由于答案可能很大,只需输出其除以M后的余数即可。
Input
第一行一个整数T,表示数据组数
对于每组数据,第一行有三个整数,分别表示n、m、M
若m不为0,则接下来一行有m对整数,p1、q1,p2、q2 ,…, pm、qm,其中第i对整数pi、qi表示第pi个人的编号必须为qi
Output
对于每组数据输出一行,若是有解则输出YES,后跟一个整数表示方案数mod M,注意,YES和数之间只有一个空格,否则输出NO
Sample Input
2
4 3 10
1 2 2 1 3 1
10 3 8882
7 9 2 9 5 10
4 3 10
1 2 2 1 3 1
10 3 8882
7 9 2 9 5 10
Sample Output
YES 4
NO
HINT
100%的数据满足:1≤T≤10,1≤n≤300,0≤m≤n,2≤M≤109,1≤pi、qi≤n 且保证pi互不相同。
Source
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 303;
typedef long long LL;
int T,n,m,C[maxn][maxn],f[maxn][maxn],sum[maxn];
bool vis[maxn][maxn]; LL P;
int Add(const LL &x,const LL &y) {return (x + y) % P;}
int Mul(const LL &x,const LL &y) {return x*y%P;}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> T;
while (T--)
{
cin >> n >> m >> P;
int res = n - m,Sum = 0;
memset(sum,0,sizeof(sum));
while (m--)
{
int x; scanf("%d%d",&x,&x); ++sum[x];
}
C[0][0] = 1;
for (int i = 1; i <= res; i++)
{
C[i][0] = 1;
for (int j = 1; j <= i; j++)
C[i][j] = Add(C[i-1][j],C[i-1][j-1]);
}
memset(f,0,sizeof(f)); f[0][0] = 1;
memset(vis,0,sizeof(vis)); vis[0][0] = 1;
for (int i = 0; i < n; i++)
{
Sum += sum[i];
for (int j = i; j <= n; j++)
{
if (!vis[i][j]) continue;
int rs = res - (j - Sum);
for (int k = 0; k <= rs; k++)
{
int Nex = j + k + sum[i+1];
if (Nex > n) break; vis[i+1][Nex] = 1;
f[i+1][Nex] = Add(f[i+1][Nex],Mul(C[rs][k],f[i][j]));
}
}
}
if (!vis[n][n]) puts("NO");
else printf("YES %d\n",f[n][n]);
}
return 0;
}