题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2302
组合数学+dp(其实我完全不会。。。
首先题目转化成<=i的至少有i个,因为如果没有i个的话后面n-i个位置肯定是不够的。
然后dp,记录下必选点和可选点个数,然后做一个n^3的dp
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> #include<cstring> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 305 #define ll long long #define eps 1e-6 using namespace std; int n,m,t; ll c[maxn][maxn],f[maxn][maxn],M; int cnt[maxn],sum[maxn]; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} return x*f; } void init(){ clr(cnt,0); clr(sum,0); clr(f,0); clr(c,0); c[0][0]=1; rep(i,1,n){ c[i][0]=1; rep(j,1,i) c[i][j]=(c[i-1][j-1]+c[i-1][j])%M; } } int main(){ t=read(); while (t--){ int x,y,gg; n=read(); m=read(); M=read(); init(); sum[0]=n-m; rep(i,1,m){ x=read(); y=read(); cnt[y]++; } gg=0; rep(i,1,n) { sum[i]=sum[i-1]+cnt[i]; if (sum[i]<i) { puts("NO"); gg=1; break; } } if (gg) continue; f[0][0]=1; rep(i,1,n) rep(j,i,sum[i]) rep(k,cnt[i],j-i+1) { f[i][j]=(f[i][j]+f[i-1][j-k]*c[sum[i]-j+k-cnt[i]][k-cnt[i]])%M; } printf("YES %lld ",f[n][n]); } return 0; }