Codeforces Round #736 (Div. 2) 部分題題解
阿新 • • 發佈:2021-08-02
D.Integers Have Friends
題目連結
簡要題解
E.The Three Little Pigs
題目連結
簡要題解
我們先來考慮一個詢問的情況,看看最終答案是什麼樣子的。
題目說道,兩個攻擊方案不同,當且僅當攻擊時刻不同,以及攻擊物件不同。
那麼我們很自然能夠想到,列舉攻擊時刻,利用組合數來計算攻擊物件的方案,求和得到答案。
對於一個詢問\(x\),它對應的答案為:$$Ans=\sum_{i=0}^n C_{3*i}^x$$
預處理組合數,每次詢問就可以\(O(n)\)解決,但是這並不能通過本題。
由於答案是組合數的和,我們可以從組合數的性質來入手。
有一個眾所周知的公式:\(C_i^j=C_{i-1}^j+C_{i-1}^{j-1}\)
把這個公式代入答案的計算公式,我們得到:
這個時候就發現了一些有意思的東西。我們設\(A[x][j]=\sum_{i=0}^{n-(j\neq 0)} C_{3*i+j}^x\),那麼上式可以寫成
\[A[x][0]=A[x-1][2]+A[x][2] \tag{1} \]同理,我們可以得到
\[A[x][1]=(A[x-1][0]-C_{3*n}^{x-1}) +(A[x][0]-C_{3*n}^x) \tag{2} \]\[A[x][2]=A[x-1][1]+A[x][1] \tag{3} \]這三個方程線性相關,我們目前無法求解。
再次利用組合數的性質,我們把\(A[x][0],A[x][1],A[x][2]\)
聯立上述四個式子就可以解方程,再預處理組合數,就可以得到\(O(1)\)遞推式。
那麼思路就很清楚了:我們先得到\(A[0][0],A[0][1],A[0][2]\)的值,然後遞推求出所有的\(A[x][0],A[x][1],A[x][2]\)。
對於每一個詢問\(x\),我們直接輸出\(A[x][0]\)。
時間複雜度\(O(n)\)。
程式碼如下:
#include<bits/stdc++.h> #define ll long long using namespace std; const int MAXN=3e6+10; const int Mod=1e9+7; int n,Qs,Ans,Inv3,Two,A[MAXN][3]; int Read() { int a=0,c=1; char b=getchar(); while(b!='-'&&(b<'0'||b>'9')) b=getchar(); if(b=='-') c=-1,b=getchar(); while(b>='0'&&b<='9') a=a*10+b-48,b=getchar(); return a*c; } int Pow(int Down,int Up) { int Ret=1,Now=Down; for(;Up>=1;Up>>=1) Up&1?Ret=1ll*Ret*Now%Mod:0,Now=1ll*Now*Now%Mod; return Ret; } namespace PRE { int Inv[MAXN],Fac[MAXN]; void Prepare() { Fac[0]=Inv[0]=1,Inv3=Pow(3,Mod-2),A[0][0]=n+1,A[0][1]=A[0][2]=n; for(int i=1;i<=3*n+1;i++) Fac[i]=1ll*Fac[i-1]*i%Mod; Inv[3*n+1]=Pow(Fac[3*n+1],Mod-2); for(int i=3*n;i>=0;i--) Inv[i]=1ll*Inv[i+1]*(i+1)%Mod; } }using namespace PRE; int C(int A,int B){ return B>A?0:1ll*Fac[A]*Inv[B]%Mod*Inv[A-B]%Mod; } int main() { n=Read(),Qs=Read(),Prepare(); for(int i=1;i<=n*3;i++) { int B0=A[i-1][0],B1=A[i-1][1],B2=A[i-1][2],Nc=C(3*n+1,i+1),Sc=C(3*n,i); B0=(1ll*B0+Mod-C(3*n,i-1))%Mod; A[i][0]=(1ll*Nc+Sc-B0+B2)*Inv3%Mod,A[i][0]=(A[i][0]+Mod)%Mod; A[i][1]=(1ll*Nc-2*Sc+2*B0+B2)*Inv3%Mod,A[i][1]=(A[i][1]+Mod)%Mod; A[i][2]=(1ll*Nc+Sc-B0-2*B2)*Inv3%Mod,A[i][2]=(A[i][2]+Mod)%Mod; } for(int i=1,S;i<=Qs;i++) S=Read(),printf("%d\n",A[S][0]); }