JZOJ-senior-5945. 【NOIP2018模擬11.02】昆特牌(gwent)
阿新 • • 發佈:2018-12-19
Time Limits: 1000 ms Memory Limits: 524288 KB Detailed Limits
Description
作為一個資深OIer,你被邀請到位於波蘭的CDPR總部參觀。但沒想到你剛一到就遇到了麻煩。昆特牌的資料庫發生了故障。原本昆特牌中有 k種卡牌和n 種陣營,為了平衡,每個陣營擁有的卡牌種數都是相等的,並且每個陣營的資料順序排列。由於故障,卡牌資料被打亂了,每個陣營現在有ai 種卡牌。因為昆特牌即將迎來重大更新,每種牌的所屬陣營並不重要,工程師只想儘快讓每個陣營擁有相同數量的卡牌。由於資料庫的結構原因,你每單位時間只能將一種牌向左邊或右邊相鄰的一個陣營移動。作為OI選手,這自然是難不倒你,但作為一名卡牌遊戲愛好者,你想知道最終的卡牌分佈有多少種方案。兩種方案不同當且僅當存在一種卡牌,它在兩種方案中所屬陣營不同。對998244353取模
Input
第一行一個整數T,表示資料組數。 接下來每組資料,第一行一個整數n ,第二行n個數,第i個數為ai ,意義見題目描述
Output
T行,每行一個數表示答案。
Sample Input
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
Solution
考慮貪心的過程,發現形成了個DAG圖,用拓撲序轉移,組合數求答案
Code
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cctype>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ll long long
using namespace std;
const int N=1010,K=1e6,P=998244353;
int T,n,num;
int a[N],b[N],d[N],q[N],last[N];
int jc[K+5],ny[K+5];
struct edge{int to,next,v;}e[2*N];
inline void read(int &n)
{
int x=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
n=w?-x:x;
}
int ksm(int a,int b)
{
int s=1;
for(;b;a=(ll)a*(ll)a%P,b>>=1)
if(b&1) s=(ll)s*(ll)a%P;
return s;
}
void pre()
{
jc[0]=1;
fo(i,1,K) jc[i]=(ll)jc[i-1]*(ll)i%P;
ny[K]=ksm(jc[K],P-2);
fd(i,K-1,0) ny[i]=(ll)ny[i+1]*(ll)(i+1)%P;
}
int C(int n,int m)
{
return (ll)jc[n]*(ll)ny[m]%P*(ll)ny[n-m]%P;
}
void link(int x,int y,int z)
{
e[++num]=(edge){y,last[x],z},last[x]=num,d[y]++;
}
int main()
{
freopen("gwent.in","r",stdin);
freopen("gwent.out","w",stdout);
pre();
read(T);
while(T--)
{
num=0,memset(last,0,sizeof(last));
read(n);
int s=0;
fo(i,1,n) read(a[i]),s+=a[i];
int v=s/n;
fo(i,1,n) b[i]=a[i]-v;
fo(i,1,n)
{
if(b[i]<0)
{
link(i+1,i,-b[i]);
b[i+1]-=abs(b[i]);
b[i]=0;
}
if(b[i]>0)
{
link(i,i+1,b[i]);
b[i+1]+=b[i];
b[i]=0;
}
}
int l=0,r=0,ans=1;
fo(i,1,n) if(!d[i]) q[++r]=i;
while(l<r)
{
int x=q[++l];
for(int w=last[x];w;w=e[w].next)
{
int y=e[w].to;
ans=(ll)ans*(ll)C(a[x],e[w].v)%P;
a[x]-=e[w].v,a[y]+=e[w].v,--d[y];
if(!d[y]) q[++r]=y;
}
}
printf("%d\n",ans);
}
}