正题
题目链接:https://www.luogu.com.cn/problem/P6672
题目大意
长度为mmm的序列aaa,有nnn个数字不是000,其他m−nm-nm−n个是000。要求重排后有多少方案满足
∀x,∑i=1xai≥i\forall x,\sum_{i=1}^xa_i\geq i∀x,i=1∑xai≥i
其中m=∑i=1naim=\sum_{i=1}^{n}a_im=∑i=1nai
1≤n≤40,1≤ai≤1051\leq n\leq 40,1\leq a_i\leq 10^51≤n≤40,1≤ai≤105
解题思路
具体数学P301页有一个ReneyReneyReney引理(虽然我还没看到):
假设一个整数序列何为111,那么它的所有循环位移中有且仅有一个满足所有的前缀和为+1+1+1
然后考虑这题,都减去一的话就是要求都为非负了,而且所有数的和为000。
怎么转换成上面那种情况,加一个进去111的话不是很行,因为有很多正数所以我们不能保证这个111排在最前面。
反着考虑,把所有数取反再加一个111的话就可以了,因为这样正数就只有111了。
所以的话它的圆排列个数就是m!m!m!个了,但是多了一个−1-1−1我们要减去这个−1-1−1的影响,其实就是多塞一个−1-1−1进去的话,就是多了m−n+1m-n+1m−n+1个了。所以答案就是
m!m−n+1\frac{m!}{m-n+1}m−n+1m!
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;
}