JZOJ5945. 【NOIP2018模拟11.02】昆特牌(gwent)

Description

作为一个资深OIer,你被邀请到位于波兰的CDPR总部参观。但没想到你刚一到就遇到了麻烦。昆特牌的数据库发生了故障。原本昆特牌中有 k种卡牌和n 种阵营,为了平衡,每个阵营拥有的卡牌种数都是相等的,并且每个阵营的数据顺序排列。由于故障,卡牌数据被打乱了,每个阵营现在有ai 种卡牌。因为昆特牌即将迎来重大更新,每种牌的所属阵营并不重要,工程师只想尽快让每个阵营拥有相同数量的卡牌。由于数据库的结构原因,你每单位时间只能将一种牌向左边或右边相邻的一个阵营移动。作为OI选手,这自然是难不倒你,但作为一名卡牌游戏爱好者,你想知道最终的卡牌分布有多少种方案。两种方案不同当且仅当存在一种卡牌,它在两种方案中所属阵营不同。对998244353取模

题解

最终每一个位置的答案都是一样的,
那么枚举一个i,
就可以知道,前i个位置,到底是可以向i+1这个位置移多少张卡牌,还是要从后面移多少张卡牌来满足i这个位置。
考虑这个位置是需要被移过来还是移走,
用组合数统计一下答案就好了。

code

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int mo=998244353;
int n,T,k,a[1000003],m,s;
ll ans,jc[1000003],ny[1000003];
char ch;
void read(int&n)
{
	for(ch=getchar();ch<'0'|| ch>'9';ch=getchar());
	for(n=0;'0'<=ch && ch<='9';ch=getchar())n=(n<<1)+(n<<3)+ch-48;
}
int ksm(ll x,int y)
{
	ll s=1;
	for(;y;y>>=1,x=x*x%mo)
		if(y&1)s=s*x%mo;
	return s;
}
ll C(int x,int y)
{
	return jc[y]*ny[x]%mo*ny[y-x]%mo;
}
int main()
{
	freopen("gwent.in","r",stdin);
	freopen("gwent.out","w",stdout);
	ny[0]=jc[0]=1;
	for(int i=1;i<1000003;i++)jc[i]=jc[i-1]*i%mo;
	ny[1000000]=ksm(jc[1000000],mo-2);
	for(int i=1000000;i;i--)ny[i-1]=ny[i]*i%mo;
	for(read(T);T;T--)
	{
		read(n);k=0;
		for(int i=1;i<=n;i++)read(a[i]),k=k+a[i];
		m=k/n;ans=1;s=0;
		for(int i=1;i<=n;i++)
		{
			s=s+a[i]-m;
			if(s<0)ans=ans*C(-s,max(m-s,a[i+1]))%mo;
				else ans=ans*C(s,m+s)%mo;
		}
		printf("%lld\n",ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值