「刷题记录」P2822 [NOIP2016 提高组] 组合数问题

本来以为很难,结果发现是道大水题
题目传送门:P2822 [NOIP2016 提高组] 组合数问题
思路:首先,你要知道什么是组合数,要知道组合数的递推公式 Cnm=Cn1m+Cn1m1,在本题中,你会发现 n,m2000nm 的范围都很小,所以我们可以直接暴力递推,但是可能会爆 long long我不知道,只是我的猜测,题中又提前给定了 k,所以我们可以在递推的过程中边推边 %k,最后,只要模后是 0,就说明这个可以被 k 整除,如果在从头到尾扫一遍记录有多少个零,那你会得到 90,我们可以用前缀和优化,每行各记一个前缀和(为什么不直接二位前缀和?因为 min(i,m)),上代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read() {
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

const int N = 2e3 + 10;

int T, k, n, m, cnt;
ll C[N][N], sum[N][N];

void pre() {
	for (int i = 0; i <= 2001; ++ i) {
		C[i][0] = 1;
		for (int j = 1; j <= i; ++ j) {
			C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % k;
		}
	}
	for (int i = 0; i <= 2001; ++ i) {
		for (int j = 1; j <= i; ++ j) {
			sum[i][j] += sum[i][j - 1];
			sum[i][j] += (C[i][j] == 0);
		}
	}
}

int main() {
	T = read(), k = read();
	pre();
	while (T --) {
		n = read(), m = read();
		ll ans = 0;
		for (int i = 0; i <= n; ++ i) {
			ans += sum[i][min(i, m)];
		}
		printf("%lld\n", ans);
	}
	return 0;
}

真的大水题

作者:yifan0305

出处:https://www.cnblogs.com/yifan0305/p/17026504.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载时还请标明出处哟!

posted @   yi_fan0305  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示