[HAOI2011] 问题C

  一个方案合法的充要条件是编号小于等于i的人至少有i个。

  然后就DP了......

  我看的神犇popoqqq的题解,哇,我居然记住了他的名字。

  设 f[i][j] 表示有 j 个人编号小于等于 i 的方案数。

  然后是很长的转移。

  还是那句话啊,是能理解,但是考场上我总不能拿着一篇题解来理解吧......

  HAOI的题通过率普遍比较高,我真的不知道是因为大家做都没思路去查题解还是因为太简单了大家都能做出来且1A......

  颓了五天过后,退役的感觉真的越来越强......

  哎,谁让我退了嫩多天......

  字符串不会......

  DP不会......

  数学题不会......

  网络流不会......

  数据结构也不会......

  一年半了我还只会刷水题......

  好吧贪心也不会......

  还不想退役......

 

// q.c

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long LL;
const int M=300+10;
int T,n,m,mod,cnt[M],sum[M],c[M][M];
long long f[M][M]; bool flag;
void input() {
	memset(cnt,0,sizeof(cnt));
	int a,b;
	scanf("%d%d%d",&n,&m,&mod);
	for(int i=1;i<=m;i++) scanf("%d%d",&a,&b),cnt[b]++;
	
}
void prepare() {
	memset(c,0,sizeof(c));
	sum[0]=n-m; flag=false;
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+cnt[i];
	for(int i=0;i<=n;i++) c[i][0]=1;
	for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) 
		c[i][j]=((LL)c[i-1][j-1]+c[i-1][j])%mod;
}
void solve() {
	memset(f,0,sizeof(f));
	f[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=i;j<=sum[i];j++)
			for(int k=cnt[i];k<=j-i+1;k++) 
				f[i][j]=f[i][j]%mod+(f[i-1][j-k]*c[sum[i]-cnt[i]-(j-k)][k-cnt[i]])%mod;
}
int main() {
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d",&T);
	for(int i=1;i<=T;i++) {
		input();
		prepare();
		solve();
		if(f[n][n]) printf("YES %d\n",f[n][n]%mod);
		else printf("NO\n");
	}
	return 0;
}

 

posted @ 2018-04-15 15:58  qjs12  阅读(87)  评论(0编辑  收藏  举报