HDU-4532 湫秋系列故事——安排座位 组合数学DP
生活随笔
收集整理的這篇文章主要介紹了
HDU-4532 湫秋系列故事——安排座位 组合数学DP
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:有來自n個專業的學生,每個專業分別有ai個同學,現在要將這些學生排成一行,使得相鄰的兩個學生來自不同的專業,問有多少種不同的安排方案。
分析:首先將所有專業的學生視作一樣的,最后再乘以各自學生的數量的階乘。排列的時候通過動態規劃來處理,設狀態為前i個系,一共有j個位置相鄰位置來自同系,然后轉移。具體見代碼注釋。
#include <cstdlib> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std;typedef long long LL; const LL mod = (int)(1e9)+7; LL A[50]; LL C[500][500]; LL dp[50][500]; // dp[i][j]表示處理到第i組,一共還有j個位置左右坐的同學來自同一個專業 int n; int seq[50];void pre() {A[0] = A[1] = 1;for (int i = 2; i < 50; ++i) {A[i] = A[i-1] * i % mod;}for (int i = 0; i < 500; ++i) {C[0][i] = 1;for (int j = 1; j <= i; ++j) {C[j][i] = (C[j][i-1] + C[j-1][i-1]) % mod;}} }int solve() {memset(dp, 0, sizeof (dp));dp[1][seq[1]-1] = 1; // 給相鄰同學來自一個系的間隙叫做粘著點 LL sum = seq[1];for (int i = 2; i <= n; ++i) {for (int j = 0; j < sum; ++j) { // sum表示處理到前i-1組最多有sum個粘著點 for (int k = 1; k <= seq[i]; ++k) { // 枚舉第i組同學被拆分成k個塊放入到隊伍中 for (int h = 0; h <= j && h <= k; ++h) {// 枚舉有h個塊放到了前面的j個粘著點,即破壞了粘著點,但顯然塊內帶來了新的粘著點 dp[i][j-h+seq[i]-k] += dp[i-1][j]*C[h][j]%mod*C[k-h][sum+1-j]%mod*C[k-1][seq[i]-1]%mod;// C[h][j]表示h個快插入了哪些粘著點// C[k-h][sum-1-j]表示k-h個塊插入了那些非粘著點,總間隙是sum+1個// C[k][seq[i]-1]表示這seq[i]個同學是如何劃分成k個塊的 dp[i][j-h+seq[i]-k] %= mod;}}}sum += seq[i]; }LL ret = dp[n][0];for (int i = 1; i <= n; ++i) {ret = ret * A[seq[i]] % mod;}return ret; }int main() {int T, ca = 0;pre();scanf("%d", &T);while (T--) {scanf("%d", &n);for (int i = 1; i <= n; ++i) {scanf("%d", &seq[i]);}printf("Case %d: %d\n", ++ca, solve());}return 0; }?
轉載于:https://www.cnblogs.com/Lyush/p/3418646.html
總結
以上是生活随笔為你收集整理的HDU-4532 湫秋系列故事——安排座位 组合数学DP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中文URL是否有利于网站SEO
- 下一篇: hibernate hbm2ddl.au