[清华集训2016]你的生命已如风中残烛——组合数学
题目链接:
题目大意:共有$m+1$张牌,其中有$n$张特殊牌,每张特殊牌有一个权值$w_{i}$表示取到这张牌能获得$w_{i}$次再抽牌的机会,保证$\sum w_{i}=m$,现在规定最后一张牌(即指定最后一张牌是哪个),初始抽第一张牌,求有多少种卡牌排列方式能使$m+1$张牌被抽完。
总方案数显然是$(m+1)!$即$m+1$个数的全排列,我们先不考虑强制固定最后一张牌的方案。将每一张牌给出一个权值表示抽到这张牌能获得的再摸牌的次数,显然普通牌的权值是$-1$,而特殊牌的权值是$w_{i}-1$,因为第一张牌抽取时不耗费摸牌次数,所以第一张牌的权值是$w_{i}$。那么求出每个位置$i$的前缀和即可表示抽完前$i$张牌后还剩的摸牌次数。显然如果一种排列合法最后一个位置(即$m+1$)的前缀和为$0$且之前每个位置的前缀和都大于$0$。那么对于一种合法排列如果将前面任意多张牌拿到最后,拿走部分的和是大于$0$的(设为$x$),那么没被移动的这些位置的前缀和就都要减$x$,没移动之前的最后一个位置的前缀和就是$-x<0$,即一定是不合法的。而对于任意一种排列,一定存在一个前缀和最小且最右的位置,对于这个位置之后的部分单独来看(即去掉这个位置及之前的部分)每个位置的前缀和一定大于0,所以只要把这个位置之后的部分拿到排列的最前面就能构造出这种排列循环同构的$(m+1)$种排列中合法的那种。所以可以得出结论对于循环同构的$m+1$个排列有且只有一个排列是合法的。合法的方案数就是$\frac{(m+1)!}{m+1}$即$m!$,而在这些合法的情况中被固定的那最后一张牌可能在普通牌的$(m+1-n)$个位置中的任意一个且在每个位置的方案数相同,所以最后的答案就是$\frac{m!}{m+1-n}$。
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<vector> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define mod 998244353 using namespace std; int n,m; int w[41]; ll ans=1ll; ll quick(int x,int y) { ll res=1ll; while(y) { if(y&1) { res=res*x%mod; } x=1ll*x*x%mod; y>>=1; } return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&w[i]); m+=w[i]; } for(int i=1;i<=m;i++) { ans=ans*i%mod; } ans=ans*quick(m-n+1,mod-2)%mod; printf("%lld",ans); }