题目链接:https://contest.ucup.ac/contest/1499/problem/8171
题目大意: $A$ 手里有个排列,$B$ 能问 $A$ 一个排列,如果排列完全匹配上,那就 $B$ 胜利,否则 $A$ 回答前 $x$ 个位置都是正确的,$x+1$ 的位置是错误的,如果 $m$ 次询问 $B$ 没有胜利就 $A$ 胜利。问 $B$ 在最优决策下, $A$ 随机拿到一个排列时 $B$ 的获胜概率。
做法
显然要对所有排列计数,而 $B$ 的最优策略就是变 $x+1$ 的位置,然后后面的位置从小到大排序(反正是随机拿一个排列,后面的部分随便一个都行,不会影响答案,从小到大好计数)。
所以问题等价于,有多少个 $n-1$ 的序列 $a$ ,满足:
$0\le a_i\le i,\sum\limits_{i=1}^{n-1}a_i\le m-1$ 。
那么等价于求:$[x^{m-1}]\frac{\prod\limits_{i=1}^{n-1}(1-x^i)}{(1-x)^{n+1}}$ ,但是注意到 $m\le n$ .
所以又等价于求: $[x^{m-1}]\frac{\prod\limits_{i=1}^{\infty}(1-x^i)}{(1-x)^{n+1}}$
分母是经典的高维前缀和,可以用组合意义快速计算 $x^i$ 的系数,分子是五边形数定理,直接算就行了。
时空复杂度:$O(n)$ 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include<bits/stdc++.h> using namespace std; typedef long long LL; const LL mod=998244353; const int N=2e7+5; LL fc[N],nfc[N]; LL C(LL x,LL y){return fc[x]*nfc[y]%mod*nfc[x-y]%mod;} int n,m; int main(){ scanf("%d%d",&n,&m);n--;m--; if(!n){ printf("1\n"); return 0; } nfc[0]=nfc[1]=fc[0]=fc[1]=1;for(int i=2;i<=n+n+1;i++)nfc[i]=(mod-mod/i)*nfc[mod%i]%mod; for(int i=2;i<=n+n+1;i++)nfc[i]=nfc[i-1]*nfc[i]%mod,fc[i]=fc[i-1]*i%mod; LL ans=0; for(int i=0;i<=n;i++){ int x=i*(3*i-1)/2; if(x>m)break; if(i&1)ans=(ans+(mod-1)*C(n+1+m-x,n+1))%mod; else ans=(ans+C(n+1+m-x,n+1))%mod; x=i*(3*i+1)/2; if(x>m || !i)continue; if(i&1)ans=(ans+(mod-1)*C(n+1+m-x,n+1))%mod; else ans=(ans+C(n+1+m-x,n+1))%mod; } printf("%lld\n",ans*nfc[n+1]%mod); return 0; }
|