正题
题目链接: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;
}