专栏文章

题解 008 题目 P2822

P2822题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miql8h95
此快照首次捕获于
2025/12/04 06:38
3 个月前
此快照最后确认于
2025/12/04 06:38
3 个月前
查看原文

题目分析

  • 数据范围中提到 0n,m2×1030\le n,m \le 2\times 10^3,因此可以想到可以使用组合数递推式 (nm)=(n1m1)+(n1m)\tbinom{n}{m}=\tbinom{n-1}{m-1}+\tbinom{n-1}{m} 进行预处理,时间复杂度 O(nm)O(nm)
  • 对于每次询问,如果暴力查找的话时间复杂度为 O(nm)O(nm),只能拿到部分分数。由于每次询问的 kk 都一样,还是访问子矩阵,可以考虑二维前缀和。如果 k(nm)k\mid\tbinom{n}{m},设矩阵 xxxn,mx_{n,m}11,否则为 00,每次询问输出 xx 前缀和即可。时间复杂度 O(1)O(1)

通过代码

CPP
#include<iostream>
using namespace std;
int t,k,n,m,c[2005][2005],x[2005][2005],a[2005][2005];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>t>>k;
	for (int i=0;i<=2000;i++){
		for (int j=0;j<=i;j++){
			if (j==0||j==i) c[i][j]=1;
			else c[i][j]=(c[i-1][j-1]%k+c[i-1][j]%k)%k; // 记得取模。
			if (c[i][j]==0) x[i][j]+=1; // 如果 c[i][j] 整除 k,将 x[i][j] 记为 1,查询时输出它的前缀和。
		}
	} // 预处理,注意边界情况。
	for (int i=0;i<=2000;i++){
		for (int j=0;j<=2000;j++){
			if (i>0&&j>0) a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+x[i][j];
			else if (i>0&&j==0) a[i][j]=a[i-1][j]+x[i][j];
			else if (i==0&&j>0) a[i][j]=a[i][j-1]+x[i][j];
			else a[i][j]=x[i][j];
		}
	} // 计算 x 数组的前缀和,同样记得注意边界情况。
	while (t--){
		cin>>n>>m;
		cout<<a[n][m]<<"\n";
	} // 每次访问,输出前缀和。
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...