[HAOI2011] Problem C - dp
Posted mollnn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2011] Problem C - dp相关的知识,希望对你有一定的参考价值。
给 (n) 个人安排座位,每个人手上有一个编号 (a_i)。从第一个人开始依次进场,每个人进场后,会从 (a_i) 往后找到第一个空着的座位就做,如果没找到则这个方案不合法。现在有 (m) 个人的座位已经确定(不同人的编号可以相同),求有多少种合法的安排方案。 (Tleq 10, n leq 300)
Solution
考虑怎样的情况的是无解的,设 (s_i) 表示编号既定的 (m) 人中编号 (geq i) 的人数,对于 (s_i>n-i+1) 显然是无解的
类似地,设 (f[i][j]) 为普通人中,编号 (geq i) 的人中确定了 (j) 个人的编号的方案数,那么考虑在确定了 (j-k) 人编号的情况下,选择 (k) 人编号为 (i) 来进行转移
[
f[i][j]=sum_{k=0}^j f[i+1][j-k]cdot C_j^k, 0leq jleq n-s_i-i+1
]
答案就是 (f[1][n-m])
注意无解一定要先判掉,不能等最后利用答案判。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 505;
int T,n,m,mod,p[N],q[N],f[N][N],c[N][N],s[N];
signed main() {
ios::sync_with_stdio(false);
cin>>T;
while(T--) {
memset(s,0,sizeof s);
memset(f,0,sizeof f);
memset(c,0,sizeof c);
cin>>n>>m>>mod;
c[0][0]=1;
for(int i=1;i<=n;i++) {
c[i][0]=1;
for(int j=1;j<=i;j++) {
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
for(int i=1;i<=m;i++) {
cin>>p[i]>>q[i];
s[q[i]]++;
}
for(int i=n;i>=0;--i) s[i]+=s[i+1];
int flag=1;
for(int i=1;i<=n;i++) if(s[i]>n-i+1) flag=0;
if(flag==0) {
cout<<"NO"<<endl;
continue;
}
f[n+1][0]=1;
for(int i=n;i>=1;--i) {
for(int j=0;j<=n-s[i]-i+1;j++) {
for(int k=0;k<=j;k++) {
(f[i][j]+=f[i+1][j-k]*c[j][k])%=mod;
}
}
}
cout<<"YES "<<f[1][n-m]<<endl;
}
}
以上是关于[HAOI2011] Problem C - dp的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2302 [HAOI2011]Problem c dp
BZOJ2298[HAOI2011]problem a DP