Wannafly挑戰賽26 F.msc的棋盤 計數DP 最小割轉換
阿新 • • 發佈:2018-12-15
題目描述
一天,msc在家裡找到了一個n×m的棋盤。
這個棋盤十分奇特,每個格子最多放一個棋子,但是你並不能看見具體的棋子都放在了哪些地方,但是有一個顯示屏可以顯示每一行每一列有多少棋子。
然而遺憾的是,由於棋盤已經放了很久,現在顯示每一行有多少棋子的部分已經壞掉了,所以msc只能知道現在的棋盤上面每一列有多少棋子。
由於msc是一個有著強烈求知慾的女生,所以她希望知道顯示屏壞掉的部分有多少種不同的可能的顯示情況。
兩種顯示情況不同,當且僅當存在至少一行在兩種情況中顯示的數值是不同的。
msc是解決不了這麼複雜的問題的,所以她告訴了你n,m以及b[1..m]表示每一列的棋子個數,請你幫她求出可能的方案數,由於答案可能很大,請將答案對1,000,000,007取模後再輸出。
輸入描述:
第一行兩個整數n和m,分別表示棋盤的行數和棋盤的列數。
第二行m個整數b[1..m],第i個數表示棋盤中第i列上的棋子個數。
輸出描述:
一行一個整數表示答案。
題解:
直接做無法下手。
貼個題解
程式碼:
#include <bits/stdc++.h> #ifdef LOCAL #define debug(x) cout<<#x<<" = "<<(x)<<endl; #else #define debug(x) 1; #endif #define chmax(x,y) x=max(x,y) #define chmin(x,y) x=min(x,y) #define lson id<<1,l,mid #define rson id<<1|1,mid+1,r #define lowbit(x) x&-x #define mp make_pair #define pb push_back #define fir first #define sec second using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; const int MOD = 1e9 + 7; const double PI = acos (-1.); const double eps = 1e-10; const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3f; const int MAXN = 5e5 + 5; int b[MAXN]; int preb[MAXN]; int least[MAXN]; ll fastpow (int a, int n) { ll ret = 1, base = a; while (n) { if (n & 1) ret = ret * base % MOD; base = base * base % MOD; n >>= 1; } return ret; } ll d[55][55][55 * 55]; ll fac[112], inv[122]; ll mul[123][123]; int main() { #ifdef LOCAL freopen ("input.txt", "r", stdin); #endif int n, m; scanf ("%d %d", &n, &m); int sum = 0; for (int i = 1; i <= m; i++) { scanf ("%d", &b[i]); sum += b[i]; } for (int i = 111; i >= 0; i--) { mul[i][i] = i; mul[i][i + 1] = 1; for (int j = i - 1; j >= 0; j--) mul[i][j] = mul[i][j + 1] * j % MOD; } fac[0] = 1; for (int i = 1; i <= 111; i++) fac[i] = fac[i - 1] * i % MOD; inv[111] = fastpow (fac[111], MOD - 2); for (int i = 111 - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % MOD; // debug(inv[0]) sort (b + 1, b + 1 + m); for (int i = 1; i <= m; i++) preb[i] = preb[i - 1] + b[i]; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) least[i] = max (least[i], sum - (n - i) * (m - j) - preb[j]); for (int i = 0; i <= n; i++) if (!least[i]) d[0][i][0] = 1; for (int i = 0; i < m; i++) { for (int j = 0; j <= n; j++) { for (int k = least[j]; k <= sum; k++) { if (!d[i][j][k]) continue; for (int l = 0; l <= n - j && k + l * (i + 1) <= sum; l++) { if (least[j + l] <= k + l * (i + 1) ) { d[i + 1][j + l][k + l * (i + 1)] += d[i][j][k] * mul[j + l][j + 1] % MOD * inv[l] % MOD; d[i + 1][j + l][k + l * (i + 1)] %= MOD; } } } } } printf ("%lld\n", d[m][n][sum]); return 0; }