题目
题意:给定n和q,q次查询,每次查询
x
i
,
1
<
=
x
i
<
=
3
∗
n
x_i,1<=x_i<=3*n
xi,1<=xi<=3∗n,求
∑
i
=
1
n
C
3
∗
i
x
i
\sum_{i=1}^{n} C_{3*i}^{x_i}
∑i=1nC3∗ixi,其中
1
<
=
n
<
=
1
0
6
,
1
<
=
q
<
=
2
∗
1
0
5
1<=n<=10^6,1<=q<=2*10^5
1<=n<=106,1<=q<=2∗105,答案对1e9+7取模。
参考
题解:不会做,只能翻译下官方的233,最难的还是构造dp方程。
定义
d
p
[
x
]
[
m
]
=
∑
i
=
0
n
−
1
C
3
∗
i
+
m
x
dp[x][m] = \sum_{i=0}^{n-1}C_{3*i+m}^x
dp[x][m]=∑i=0n−1C3∗i+mx,则
a
n
s
[
x
]
=
d
p
[
x
]
[
0
]
+
C
3
∗
n
x
ans[x] = dp[x][0] + C_{3*n}^x
ans[x]=dp[x][0]+C3∗nx,此外,有
d
p
[
x
]
[
0
]
+
d
p
[
x
]
[
1
]
+
d
p
[
x
]
[
2
]
=
∑
i
=
0
3
∗
n
−
1
C
i
x
dp[x][0]+dp[x][1]+dp[x][2]=\sum_{i=0}^{3*n-1}C_i^x
dp[x][0]+dp[x][1]+dp[x][2]=∑i=03∗n−1Cix,而
C
3
∗
n
x
+
1
C_{3*n}^{x+1}
C3∗nx+1
=
C
3
∗
n
−
1
x
+
C
3
∗
n
−
1
x
+
1
=C_{3*n-1}^{x}+C_{3*n-1}^{x+1}
=C3∗n−1x+C3∗n−1x+1
=
C
3
∗
n
−
1
x
+
C
3
∗
n
−
2
x
+
C
3
∗
n
−
2
x
+
1
=C_{3*n-1}^{x}+C_{3*n-2}^{x}+C_{3*n-2}^{x+1}
=C3∗n−1x+C3∗n−2x+C3∗n−2x+1
=
∑
i
=
0
3
∗
n
−
1
C
i
x
=\sum_{i=0}^{3*n-1}C_i^x
=∑i=03∗n−1Cix
所以有以下(1)式。加上组合数的
C
m
x
=
C
m
−
1
x
+
C
m
−
1
x
−
1
C_m^x=C_{m-1}^x+C_{m-1}^{x-1}
Cmx=Cm−1x+Cm−1x−1,可以得到(2)和(3)式。
d
p
[
x
]
[
0
]
+
d
p
[
x
]
[
1
]
+
d
p
[
x
]
[
2
]
=
C
3
∗
n
x
+
1
dp[x][0]+dp[x][1]+dp[x][2]=C_{3*n}^{x+1}
dp[x][0]+dp[x][1]+dp[x][2]=C3∗nx+1 (1)
d
p
[
x
]
[
1
]
=
d
p
[
x
]
[
0
]
+
d
p
[
x
−
1
]
[
0
]
dp[x][1]=dp[x][0]+dp[x-1][0]
dp[x][1]=dp[x][0]+dp[x−1][0] (2)
d
p
[
x
]
[
2
]
=
d
p
[
x
]
[
1
]
+
d
p
[
x
−
1
]
[
1
]
dp[x][2]=dp[x][1]+dp[x-1][1]
dp[x][2]=dp[x][1]+dp[x−1][1] (3)
d
p
[
0
]
[
0
]
=
d
p
[
0
]
[
1
]
=
d
p
[
0
]
[
2
]
=
n
dp[0][0]=dp[0][1]=dp[0][2]=n
dp[0][0]=dp[0][1]=dp[0][2]=n(4)
利用上面3个式子,和初始式子(4),我们就可以愉快的递推了。
但还有我们还需要预处理
C
3
∗
n
i
C_{3*n}^{i}
C3∗ni,考虑到取模运算,我们还需要预处理1到3*n关于mod的逆,这里要用上线性递推,预处理线性逆元(图源)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1000010;
const int mod = 1e9 + 7;
int n, q, x;
int C[3 * maxn];
int inv[3 * maxn];
int dp[3 * maxn][3];
/*
* 0 <= a, b < mod
*/
int sub_mod(int a, int b) {
int res = a - b;
if (res < 0) res += mod;
return res;
}
/*
* 0 <= a, b < mod
*/
int add_mod(int a, int b) {
int res = a + b;
if (res >= mod) res -= mod;
return res;
}
int mul(int a, int b) {
return 1LL * a * b % mod;
}
void print(int N) {
printf("C:\n");
for (int i = 0; i <= N; ++i) {
printf("%d\n", C[i]);
}
printf("dp:\n");
for (int i = 0; i <= N; ++i) {
printf("%d %d %d\n", dp[i][0], dp[i][1], dp[i][2]);
}
printf("-------------\n");
}
void init() {
C[0] = 1;
int N = 3 * n;
inv[0]=1;
inv[1]=1;
for (int i = 2; i <= N; ++i) {
inv[i] = mul(mod - mod / i, inv[mod%i]);
}
for (int i = 1; i <= N; ++i) {
// C[i] = C[i-1] * (N - i + 1) / i;
C[i] = mul(mul(C[i-1], (N - i + 1)), inv[i]);
}
memset(dp, 0, sizeof(dp));
dp[0][0] = dp[0][1] = dp[0][2] = n;
for (int i = 1; i <= N; ++i) {
// dp[i][0] = (C[i+1] - 2 * dp[i-1][0] - dp[i-1][1]) / 3;
int tmp = sub_mod(C[i+1], mul(2, dp[i-1][0]));
tmp = sub_mod(tmp, dp[i-1][1]);
dp[i][0] = mul(tmp, inv[3]);
dp[i][1] = add_mod(dp[i][0], dp[i-1][0]);
dp[i][2] = add_mod(dp[i][1], dp[i-1][1]);
}
}
int main() {
scanf("%d%d", &n, &q);
init();
// print(3 * n);
while (q--) {
scanf("%d", &x);
printf("%d\n", add_mod(dp[x][0], C[x]));
}
}