首页 > 其他 > 详细

洛谷 P2822 组合数问题

时间:2020-03-16 10:47:19      阅读:58      评论:0      收藏:0      [点我收藏+]

P2822 组合数问题

题目描述

技术分享图片

 

 

 

输入格式

第一行有两个整数 t,kt,k,其中 tt 代表该测试点总共有多少组测试数据,kk 的意义见问题描述。

接下来 tt 行每行两个整数 n,mn,m,其中 n,mn,m 的意义见问题描述。

输出格式

技术分享图片

 

说明/提示

技术分享图片

 

 

我们知道,在二项式定理中,每一项的二项式系数都相应的对应着杨辉三角的某一行

如图:

技术分享图片

 

本题的测试点只在2000的范围内,所以可以打表,将2000以内的排列数全部求出来。

之后如果用二次遍历来排查能不能整除,复杂度会比较大,会有可能爆时间(事实上也爆时间了),只能得90分,

但是,可以用求前缀和来简化,

技术分享图片

 

 本题的前缀和公式也相应地是:s[x][y]=b[x-1][y]+b[x][y-1]-b[x-1][y-1] ;

代码如下:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<math.h>usingnamespacestd; int k,a[5000][5000]; int s[5000][5000]; void st(int k) { a[1][1]=1; for(int i=1;i<=2000;i++) { a[i][0]=1; } for(int i=2;i<=2000;i++) { for(int j=1;j<=i;j++) { a[i][j]=(a[i-1][j-1]%k+a[i-1][j]%k)%k; } } for(int i=2;i<=2000;i++) { for(int j=1;j<=i;j++) { s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]; if(a[i][j]==0) { s[i][j]++; } } s[i][i+1]=s[i][i]; } } int main(void) { int t,k; cin>>t>>k; st(k); while(t--) { int n,m; cin>>n>>m; if(m>n) cout<<s[n][n]<<endl; elsecout<<s[n][m]<<endl; } return0; }

这里相应的,只要输出s[n][m],即输出前缀和,即可得到正确答案。

这里的优化,最关键的就是这里的前缀和求值,重在理解!!!

可以理解为:

用局部面积之和,再加上自己,减去重复的地方,即得前缀和。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<math.h>usingnamespacestd; int k,a[5000][5000]; int s[5000][5000]; void st(int k) { a[1][1]=1; for(int i=1;i<=2000;i++) { a[i][0]=1; } for(int i=2;i<=2000;i++) { for(int j=1;j<=i;j++) { a[i][j]=(a[i-1][j-1]%k+a[i-1][j]%k)%k; } } for(int i=2;i<=2000;i++) { for(int j=1;j<=i;j++) { s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]; if(a[i][j]==0) { s[i][j]++; } } s[i][i+1]=s[i][i]; } } int main(void) { int t,k; cin>>t>>k; st(k); while(t--) { int n,m; cin>>n>>m; if(m>n) cout<<s[n][n]<<endl; elsecout<<s[n][m]<<endl; } return0; }

洛谷 P2822 组合数问题

原文:https://www.cnblogs.com/jd1412/p/12501859.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!