1. 程式人生 > 其它 >Codeforces Round #736 (Div. 2) 部分題題解

Codeforces Round #736 (Div. 2) 部分題題解

D.Integers Have Friends

題目連結

Integers Have Friends

簡要題解

E.The Three Little Pigs

題目連結

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}\)
把這個公式代入答案的計算公式,我們得到:

\[\sum_{i=0}^n C_{3*i}^x =\sum_{i=0}^n C_{3*i-1}^x+\sum_{i=0}^n C_{3*i-1}^{x-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]\)

加起來,可以得到:

\[A[x][0]+A[x][1]+A[x][2]=\sum_{i=0}^{3*n}C_{i}^x=C_{3*n+1}^{x+1} \tag{4} \]

聯立上述四個式子就可以解方程,再預處理組合數,就可以得到\(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]);
}