题目
题目链接:https://codeforces.com/contest/1548/problem/C
给定 (n,Q),(Q) 次询问,每次询问给出 (k),求
[sum^{n}_{i=1}inom{3i}{k}mod 10^9+7
]
(nleq 10^6,Qleq 2 imes 10^5)。
思路
设 (f[i][j]=sum^{n-1}_{k=0}inom{3k+j}{i}mod 10^9+7) 的值。其中 (jin [0,2])。这样的话,答案就是 (f[k][0]+inom{3n}{k}) 了。
考虑怎么转移。根据 (inom{n}{m}=inom{n-1}{m}+inom{n-1}{m-1}),有
[f[i][1]=f[i][0]+f[i-1][0]
]
[f[i][2]=f[i][1]+f[i-1][1]
]
然后观察到
[f[i][0]+f[i][1]+f[i][2]=sum^{3n-1}_{j=0}inom{j}{i}=inom{3n}{i+1}
]
就可以进行 dp 预处理出 (f[i][j]) 了。
至于 (sum^{3n-1}_{j=0}inom{j}{i}=inom{3n}{i+1}) 的原因,考虑组合意义,“从 (3n) 个物品选出 (i+1) 个”。当最后一个被选择的物品是第 (k) 个时,方案数就等于 (inom{k-1}{i})。
时间复杂度 (O(n+Q))。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3000010,MOD=1e9+7,inv3=333333336;
int n,Q,f[N][3];
ll fac[N],inv[N];
ll fpow(ll x,ll k)
{
ll ans=1;
for (;k;k>>=1,x=x*x%MOD)
if (k&1) ans=ans*x%MOD;
return ans;
}
ll C(int n,int m)
{
if (n<m) return 0;
return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int main()
{
scanf("%d%d",&n,&Q);
fac[0]=inv[0]=1;
for (int i=1;i<=3*n;i++) fac[i]=fac[i-1]*i%MOD;
inv[3*n]=fpow(fac[3*n],MOD-2);
for (int i=3*n-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%MOD;
f[0][0]=f[0][1]=f[0][2]=n;
for (int i=1;i<=3*n;i++)
{
f[i][0]=(C(3*n,i+1)-f[i-1][1]-f[i-1][0]*2)*inv3%MOD;
f[i][1]=(f[i][0]+f[i-1][0])%MOD;
f[i][2]=(f[i][1]+f[i-1][1])%MOD;
}
while (Q--)
{
int k;
scanf("%d",&k);
cout<<((f[k][0]+C(3*n,k))%MOD+MOD)%MOD<<"
";
}
return 0;
}