AT_agc053_c [AGC053C] Random Card Game 题解
首先容易发现含有 \(2n\) 的那一堆不会被删掉,记其为 \(a\),另一堆为 \(b\)。记 \(p_i\) 表示最小的 \(j\) 满足 \(j\ge i\land a_j>b_i\),那么至少要在 \(a\) 堆中删除 \(\max\{p_i-i,0\}\) 个数才能删除 \(b_i\),那么答案就是 \(n+\max\{p_i-i\}\)。
记 \(f(x)\) 表示操作次数 \(\le x+n\) 的概率,那么期望操作次数就是 \(2n-\sum_{i=0}^{n-1}f(i)\),容易得到:
\[f(x)=\prod_{i=1}^n \left(1-\frac{1}{i+\min\{i+x,n\}}\right)
\]
分奇偶处理前/后缀逆元积即可,时间复杂度 \(\mathcal O(n+\log B)\)。
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define mxn 2000003
#define md 1000000007
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int n;
ll ans,inv[mxn],d[mxn],d1[mxn],d2[mxn],d3[mxn],d4[mxn];
ll power(ll x,int y){
ll ans=1;
for(;y;y>>=1){
if(y&1)ans=ans*x%md;
x=x*x%md;
}
return ans;
}
ll solve(int k){
ll ans=d[n*2-k+1];
if(k&1)ans=ans*d1[n*2-k]%md*d3[k+1]%md;
else ans=ans*d2[n*2-k]%md*d4[k+1]%md;
return ans;
}
signed main(){
cin>>n,ans=n;
inv[1]=1;
rep(i,2,n<<1)inv[i]=inv[md%i]*(md-md/i)%md;
d[(n<<1)+1]=1;
drep(i,(n<<1),1)d[i]=d[i+1]*(1-inv[i])%md;
d1[1]=1;
rep(i,2,(n<<1)){
if(i&1)d1[i]=d1[i-1]*(1-inv[i])%md;
else d1[i]=d1[i-1];
}
d3[n<<1]=power(d1[n<<1],md-2);
drep(i,n<<1,2){
if(i&1)d3[i-1]=d3[i]*(1-inv[i])%md;
else d3[i-1]=d3[i];
}
d2[1]=1;
rep(i,2,(n<<1)){
if(!(i&1))d2[i]=d2[i-1]*(1-inv[i])%md;
else d2[i]=d2[i-1];
}
d4[n<<1]=power(d2[n<<1],md-2);
drep(i,n<<1,1){
if(!(i&1))d4[i-1]=d4[i]*(1-inv[i])%md;
else d4[i-1]=d4[i];
}
rept(i,0,n)ans=(ans-solve(i))%md;
cout<<(ans*2%md+md)%md;
return 0;
}