NOIp提高组 2016 组合数问题————组合数学+前缀和

题解:本题主要考查组合数学+前缀和。
简要题意:给 n , m , k n,m,k n,m,k,对于所有的 0 ≤ i ≤ n , 0 ≤ j ≤ m i n ⁡ ( i , m ) 0≤i≤n,0≤j≤min⁡(i,m) 0in,0jmin(i,m),求有多少对 ( i , j ) (i,j) (i,j)满足 C i j C_i^j Cij k k k的倍数。
1.组合数学:杨辉三角第 i i i行第 j j j列的值就是 C i j C_i^j Cij的值,所以我们把杨辉三角打出来。
公式: c [ i ] [ j ] = c [ i − 1 ] [ j ] + c [ i − 1 ] [ j − 1 ] c[i][j]=c[i-1][j]+c[i-1][j-1] c[i][j]=c[i1][j]+c[i1][j1]
2.前缀和:如果我们不加优化就只得90分(不要问我怎么知道),所以要用前缀和优化。优化很巧妙,用二维前缀和,每一次查询就由 O ( n ) O(n) O(n)降到 O ( 1 ) O(1) O(1)
代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
int c[2333][2333],s[2333][2333];
int n,m,k,t; 
using namespace std;
void YH()
{
	c[0][0]=1;
	c[1][0]=c[1][1]=1;
	for(int i=0;i<=2323;i++)c[i][0]=1;
	
	for(int i=2;i<=2323;i++)
	for(int j=1;j<=i;j++)
		c[i][j]=(c[i-1][j]+c[i-1][j-1])%k;//杨辉三角
		
	for(int i=2;i<=2323;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(c[i][j]==0)s[i][j]++;
	   }
	    s[i][i+1]=s[i][i];
    }
}
int main()
{
	cin>>t>>k;
	YH();
	for(int i=1;i<=t;i++)
	{
		cin>>n>>m;
		if(m>n)cout<<s[n][n]<<endl;
		else cout<<s[n][m]<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值