Lucky Pascal Triangle Gym - 102091F(分块+递归)

传送门:QAQ

 

题意:给你一个n层的杨辉三角,让你求出里面7的倍数的个数有几个。n的数据范围为10^18,有10^5组数据

 

思路:首先我们先打个表,然后把7的倍数都标记出来

 

你会发现每个块内回有两种组成,一种是属于这个块的大块,另一个就是上个块。

这样我们可以先预处理每个块里7的倍数的数量,然后根据给的行数去递归求解

比如:

如果我们要求198行杨辉三角的解,首先明确的是196行前的数量我们都是可以预处理并且直接算出来的,然后196-198的大块的数量我们也可以知道(因为我们知道大块的长度),然后我们需要求的就是小块内7的倍数的数量,由于小的块就是上一个大块,我们只要求出上一个块对应行前的7的倍数的数量即可,按此递归即可。

注意要先处理出2的逆元,不然会t。

 

附上代码:

#include<cstdio>
#include<map>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
typedef long long LL;

//
//long long bn[1000][1000];
//int main(void) {
//	memset(bn, 0, sizeof(bn));
//	long long sum = 0;
//	for (int i = 0; i <= 1000;i++) {
//		printf("%d-", i);
//		if (i == 0) {
//			bn[0][0] = 1;
//			//printf("1" );
//		}
//		else {
//			bn[i][0] = 1;
//			printf("1");
//			for (int z = 1; z <= i-1; z++) {
//				bn[i][z] = (bn[i - 1][z] + bn[i - 1][z - 1])%7;
//				if (bn[i][z] == 0) {
//					sum++;
//					printf("*");
//				}
//				else {
//					printf("1");
//				}
//			}
//			bn[i][i] = 1;
//			printf("1");
//			printf("*****%lld", sum);
//		}
//		//printf("%lld\n", sum);
//		printf("\n");
//	}
//	return 0;
//}

const LL mod = 1e9 + 7;
LL ax[40];
LL gx[40] = { 0,7 };
LL mi2;
LL powmod(LL a, LL b, LL m) {
	LL ans = 1;
	while (b > 0) {
		if (b & 1) {
			ans = ans*a%m;
		}
		a = a*a%m;
		b >>= 1;
	}
	return ans;
}
LL solve(LL num, LL cen) {
	if (num == 0) {
		return 0;
	}
	LL gg = cen / gx[num];
	LL ans = cen % gx[num];
	LL sum1 = (gx[num] % mod - 1 + mod) % mod*(gx[num] % mod) % mod*mi2 % mod;
	LL sum2 = (1 + gg)*(gg) % mod*ax[num - 1] % mod*mi2 % mod;
	LL sum4;
	if (gg <= 1) {
		sum4 = 0;
	}
	else {
		sum4 = (gg - 1)*(1 + (gg - 2) + 1) % mod*sum1 % mod*mi2 % mod;
	}
	LL sum3 = ((gx[num] % mod - 1 + gx[num] % mod - 1) % mod - ans%mod + 1 + mod) % mod*(ans%mod) % mod*mi2 % mod;
	LL sum5 = solve(num - 1, ans);
	return (((sum4 + sum2) % mod + sum3*gg%mod) % mod + sum5 % mod*(gg + 1) % mod) % mod;
}
int main(void) {
	LL t1 = 7 * 7;
	LL t2 = 21 * 21;
	ax[0] = 0;
	ax[1] = 21 * 21;
	mi2 = powmod(2, mod - 2, mod) % mod;
	int ff = 1;
	for (int i = 2; i <= 22; i++) {
		gx[i] = t1;
		//printf("%lld\n", gx[i]);
		ax[i] = (ax[i - 1] * 28 % mod + (t1 - 1 + 1) % mod*((t1 - 1) % mod) % mod * 21 % mod * mi2) % mod;
		t2 = ax[i];
		t1 = t1 * 7;
	}
	int t;
	scanf("%d", &t);
	while (t--) {
		LL n;
		scanf("%lld", &n);
		int ans;
		printf("Case %d: ", ff++);
		for (int i = 0; i <= 22; i++) {
			if (gx[i] > n) {
				ans = i - 1;
				break;
			}
		}
		if (ans == -1) {
			printf("0\n");
			continue;
		}
		printf("%lld\n", solve(ans, n + 1));
	}
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值