jozj5945. 【NOIP2018模擬11.02】昆特牌
阿新 • • 發佈:2018-12-19
5945. 【NOIP2018模擬11.02】昆特牌
Description 作為一個資深OIer,你被邀請到位於波蘭的CDPR總部參觀。但沒想到你剛一到就遇到了麻煩。昆特牌的資料庫發生了故障。原本昆特牌中有 k種卡牌和n 種陣營,為了平衡,每個陣營擁有的卡牌種數都是相等的,並且每個陣營的資料順序排列。由於故障,卡牌資料被打亂了,每個陣營現在有ai 種卡牌。因為昆特牌即將迎來重大更新,每種牌的所屬陣營並不重要,工程師只想儘快讓每個陣營擁有相同數量的卡牌。由於資料庫的結構原因,你每單位時間只能將一種牌向左邊或右邊相鄰的一個陣營移動。作為OI選手,這自然是難不倒你,但作為一名卡牌遊戲愛好者,你想知道最終的卡牌分佈有多少種方案。兩種方案不同當且僅當存在一種卡牌,它在兩種方案中所屬陣營不同。對998244353取模
Input 第一行一個整數T,表示資料組數。 接下來每組資料,第一行一個整數n ,第二行n個數,第i個數為ai ,意義見題目描述
Output T行,每行一個數表示答案。
Sample Input1 3 3 2 1 3 3 1 2 3 3 3 2 1
Sample Input2 4 3 8 1 0 4 5 0 1 2 4 0 4 0 0 4 1 1 6 0
Sample Output
Sample Output1 3 9 9
樣例解釋 對於第一組資料,初始為{{1,2}{3}{4,5,6}} 移動結束後為 {{1,2}{3,4}{5,6}},{{1,2}{3,6}{4,5}},{{1,2}{3,5}{4,6}}
Sample Output2 1120 30 24 270
Data Constraint
分析:求均攤紙牌的方案數。 考慮貪心的過程,轉移形成了一個DAG。在圖上DP即可。
程式碼
#include <cstdio> #define ll long long #define mo 998244353 #define N 1000005 using namespace std; ll pow[N],ny[N],a[N],sum[N]; int T,n; ll ksm(ll x, ll y) { ll base = x, r = 1; while (y) { if (y & 1) r = (r * base) % mo; base = (base * base) % mo; y /= 2; } return r; } ll C(int n, int m) {return pow[n] * ny[m] % mo * ny[n - m] % mo;} int main() { freopen("gwent.in","r",stdin); freopen("gwent.out","w",stdout); scanf("%d", &T); pow[0] = ny[0] = 1; for (int i = 1; i <= N; i++) { pow[i] = pow[i - 1] * i % mo; ny[i] = ksm(pow[i], mo - 2); } while (T--) { scanf("%d", &n); ll ans = 1; for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); sum[i] = sum[i - 1] + a[i]; } ll x = sum[n] / n; for (int i = 1; i <= n; i++) { ll now = sum[i] - x * i; if (now >= 0) { ans = (ans * C(a[i], now)) % mo; a[i + 1] += now; a[i] -= now; } else { ll s = x * (i + 1) - sum[i]; ans = (ans * C(s, -now)) % mo; } } printf("%lld\n", ans); } }