P6672-[清华集训2016]你的生命已如风中残烛【结论】

正题

题目链接:https://www.luogu.com.cn/problem/P6672


题目大意

长度为\(m\)的序列\(a\),有\(n\)个数字不是\(0\),其他\(m-n\)个是\(0\)。要求重排后有多少方案满足

\[\forall x,\sum_{i=1}^xa_i\geq i \]

其中\(m=\sum_{i=1}^{n}a_i\)

\(1\leq n\leq 40,1\leq a_i\leq 10^5\)


解题思路

具体数学P301页有一个\(Reney\)引理(虽然我还没看到):
假设一个整数序列何为\(1\),那么它的所有循环位移中有且仅有一个满足所有的前缀和为\(+1\)

然后考虑这题,都减去一的话就是要求都为非负了,而且所有数的和为\(0\)

怎么转换成上面那种情况,加一个进去\(1\)的话不是很行,因为有很多正数所以我们不能保证这个\(1\)排在最前面。

反着考虑,把所有数取反再加一个\(1\)的话就可以了,因为这样正数就只有\(1\)了。

所以的话它的圆排列个数就是\(m!\)个了,但是多了一个\(-1\)我们要减去这个\(-1\)的影响,其实就是多塞一个\(-1\)进去的话,就是多了\(m-n+1\)个了。所以答案就是

\[\frac{m!}{m-n+1} \]


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll P=998244353;
ll n,m,ans;
ll power(ll x,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*x%P;
		x=x*x%P;b>>=1;
	}
	return ans;
}
signed main()
{
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		ll x;scanf("%lld",&x);
		m+=x;
	}
	ans=1;
	for(ll i=1;i<=m;i++)ans=ans*i%P;
	printf("%lld\n",ans*power(m-n+1,P-2)%P);
	return 0;
}
posted @ 2021-04-02 21:52  QuantAsk  阅读(53)  评论(0编辑  收藏  举报