[清华集训2016] 你的生命已如风中残烛

考虑我们对所有数都减一,那么我们求的就是这个每个前缀和都是大于等于0的数列数量。
那么有这么一个定理:

如果有一个数列其和为1,那么在他的循环移位上有且仅有一个满足前缀和全大于等于0

那么我们发现这个原题是和为 \(0\) ,那么我们需要找到一个可行的方案放入一个1,且其一定是循环移位的第一个数,即没有数比他大,所以我们直接取反,再把他这个1加在这个前面。

那我们考虑圆排列,那么就是\((m + 1 - 1)! = (m)!\),考虑第一个\(1\)\(m - n + 1\) 个,即有这个 \( (m - n + 1)!\)排列,因为是多加了一个所以其实多算了 \((m - n + 1)\)

#include<iostream>
#include<cstdio>
#define ll long long 
#define N 50
#define mod 998244353

ll num[N],m;
ll n;

int main(){
	scanf("%lld",&n);
	for(int i = 1;i <= n;++i)
	scanf("%lld",&num[i]),m += num[i];
	ll s = 1;
	for(int i = 1;i <= m;++i)
	if(i != (m - n + 1))
	s = (s * i % mod) % mod;
	std::cout<<s<<std::endl;
}
posted @ 2021-09-13 21:01  fhq_treap  阅读(173)  评论(0编辑  收藏  举报