BZOJ2302 [HAOI2011]Problem c 【dp】
題目
給n個人安排座位,先給每個人一個1~n的編號,設第i個人的編號為ai(不同人的編號可以相同),接著從第一個人開始,大家依次入座,第i個人來了以后嘗試坐到ai,如果ai被占據了,就嘗試ai+1,ai+1也被占據了的話就嘗試ai+2,……,如果一直嘗試到第n個都不行,該安排方案就不合法。然而有m個人的編號已經確定(他們或許賄賂了你的上司...),你只能安排剩下的人的編號,求有多少種合法的安排方案。由于答案可能很大,只需輸出其除以M后的余數即可。
輸入格式
第一行一個整數T,表示數據組數
對于每組數據,第一行有三個整數,分別表示n、m、M
若m不為0,則接下來一行有m對整數,p1、q1,p2、q2 ,…, pm、qm,其中第i對整數pi、qi表示第pi個人的編號必須為qi
輸出格式
對于每組數據輸出一行,若是有解則輸出YES,后跟一個整數表示方案數mod M,注意,YES和數之間只有一個空格,否則輸出NO
輸入樣例
2
4 3 10
1 2 2 1 3 1
10 3 8882
7 9 2 9 5 10
輸出樣例
YES 4
NO
提示
100%的數據滿足:1≤T≤10,1≤n≤300,0≤m≤n,2≤M≤109,1≤pi、qi≤n 且保證pi互不相同。
題解
容易發現其實這是插入順序無關的
位置插入是否合法,只要看這個位置及其之后是否坐滿
直接難以計算一個位置之后坐了多少
但是坐到一個位置前的人的編號一定比這個位置小
如果編號為一個位置及其之前的位置的人數小于這個位置的編號,說明前面的座位一定坐不滿,那么就代表著不合法
所以我們設\(f[i][j]\)表示編號為第\(i\)個位置及其之前的人數有\(j\)人的方案數
就可以枚舉\(i\)號位坐了多少人進行轉移了
我們記一個\(sum[i]\)數組表示固定編號\(<=i\)的人數
并且將沒有固定編號的人數記為編號\(0\)
這樣子一個位置可以坐的人數就在范圍\([num[i],sum[i]]\)以內了,其中\(num[i]\)指固定編號為\(i\)的人數
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define LL long long int #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts(""); using namespace std; const int maxn = 305,maxm = 100005,INF = 1000000000; inline int read(){int out = 0,flag = 1; char c = getchar();while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}return out * flag; } int P,n,m; LL C[maxn][maxn],f[maxn][maxn],sum[maxn],num[maxn]; void init(){memset(f,0,sizeof(f));memset(sum,0,sizeof(sum));memset(num,0,sizeof(num));C[0][0] = 1;for (int i = 1; i <= n; i++){C[i][0] = C[i][i] = 1;for (int j = 1; j <= (i >> 1); j++)C[i][j] = C[i][i - j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;} } int main(){int T = read(),flag;while (T--){n = read(); m = read(); P = read(); flag = true;init(); sum[0] = n - m;for (int i = 1; i <= m; i++) read(),num[read()]++;for (int i = 1; i <= n; i++){sum[i] = sum[i - 1] + num[i];if (sum[i] < i) {flag = false; break;}}if (!flag){puts("NO"); continue;}f[0][0] = 1;for (int i = 1; i <= n; i++){for (int j = i; j <= sum[i]; j++){for (int k = num[i]; k <= j - i + 1; k++)f[i][j] = (f[i][j] + f[i - 1][j - k] * C[sum[i] - num[i] - (j - k)][k - num[i]] % P) % P;}}printf("YES %lld\n",f[n][n]);}return 0; }轉載于:https://www.cnblogs.com/Mychael/p/8881630.html
總結
以上是生活随笔為你收集整理的BZOJ2302 [HAOI2011]Problem c 【dp】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HALCON示例程序forest.hde
- 下一篇: 黑苹果efi引导文件大全_经历了无数次失