日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ2302 [HAOI2011]Problem c 【dp】

發布時間:2023/12/10 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。