The Three Little Pigs(数论/逆元/dp)

题目
题意:给定n和q,q次查询,每次查询 x i , 1 < = x i < = 3 ∗ n x_i,1<=x_i<=3*n xi1<=xi<=3n,求 ∑ i = 1 n C 3 ∗ i x i \sum_{i=1}^{n} C_{3*i}^{x_i} i=1nC3ixi,其中 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<=2105,答案对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=0n1C3i+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]+C3nx,此外,有
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=03n1Cix,而
C 3 ∗ n x + 1 C_{3*n}^{x+1} C3nx+1
= C 3 ∗ n − 1 x + C 3 ∗ n − 1 x + 1 =C_{3*n-1}^{x}+C_{3*n-1}^{x+1} =C3n1x+C3n1x+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} =C3n1x+C3n2x+C3n2x+1
= ∑ i = 0 3 ∗ n − 1 C i x =\sum_{i=0}^{3*n-1}C_i^x =i=03n1Cix
所以有以下(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=Cm1x+Cm1x1,可以得到(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]=C3nx+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[x1][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[x1][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} C3ni,考虑到取模运算,我们还需要预处理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]));
	}
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值