AT2070-[ARC061D]3人でカードゲーム/Card Game for Three【計數,組合數學】
阿新 • • 發佈:2021-11-09
正題
題目連結:https://www.luogu.com.cn/problem/AT2070
題目大意
有三堆卡牌各有\(n,m,k\)張,每張上寫了\(a/b/c\),對於第\(1/2/3\)堆卡牌。然後開始從第一堆拿牌,然後根據拿到的牌在對應的堆拿牌。
如果到一堆拿牌時沒有牌就結束,求第一張牌結束的方案數。
\(1\leq n,m,k\leq 3\times 10^5\)
解題思路
顯然牌的序列我們不是很好處理因為不是順序拿的,我們可以操作每次取的堆的編號序列。
顯然它的長度不是固定的,我們列舉其長度\(n+i\)(也就是除了\(n\)個\(1\)以外有\(i\)個其他的)。
然後答案就是
\[\sum_{i=0}^{m+k}3^{m+k-i}\binom{n+i-1}{i}\sum_{i-k\leq j\leq m}\binom{i}{j} \]後面那個很難處理但是注意到區間的範圍是每次向前移動,而且上面那個值是每次加一,暴力拆開
然後就可以\(O(n)\)遞推了。
時間複雜度:\(O(n+m+k)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e6+10,P=1e9+7; ll n,m,k,ans,fac[N],inv[N],s[N],pw[N]; ll C(ll n,ll m) {return fac[n]*inv[m]%P*inv[n-m]%P;} signed main() { fac[0]=inv[0]=inv[1]=pw[0]=1; for(ll i=1;i<N;i++)pw[i]=pw[i-1]*3ll%P; for(ll i=2;i<N;i++)inv[i]=P-inv[P%i]*(P/i)%P; for(ll i=1;i<N;i++)fac[i]=fac[i-1]*i%P,inv[i]=inv[i-1]*inv[i]%P; scanf("%lld%lld%lld",&n,&m,&k);s[0]=1;ans=pw[m+k]; for(ll i=1;i<=m+k;i++){ s[i]=2*s[i-1]%P; if(i>m)(s[i]+=P-C(i-1,m))%=P; if(i>k)(s[i]+=P-C(i-1,i-k-1))%=P; (ans+=C(n+i-1,i)*s[i]%P*pw[m+k-i])%=P; } printf("%lld\n",ans); return 0; }