……

解题报告:luogu P2822

题目链接:P2822 组合数问题
很水的一道二维前缀和,我们只需要组合数递推(杨辉三角)就好了,就是这个:

\[C_n^m=C_{n-1}^m+C_{n-1}^{m-1} \]

就好了,边递推边取膜,二维前缀和维护和即可。
(我不会告诉你我的循环边界写错\(WA\)\(n\)次。

\(Code\):

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long f[2005][2005],sum[2005][2005];
long long ch[2005][2005],cs[2005][2005];
int t,n,m,k;
int main()
{
	//freopen("data.in","r",stdin);
	//freopen("baoli.out","w",stdout);
	scanf("%d%d",&t,&k);
	for(int i=0;i<=2001;i++)
	{
		f[i][0]=1;
		ch[i][0]=0;
		ch[0][i]=0;
		cs[0][i]=0;
		cs[0][i]=0;
		sum[i][0]=0;
		sum[0][i]=0;
	}
	for(int i=1;i<=2001;i++)
	{
		for(int j=1;j<=i;j++)
		{
			f[i][j]=(f[i-1][j]+f[i-1][j-1])%k;
		}
	}
	for(int i=1;i<=2001;i++)
	{
		for(int j=1;j<=i;j++)
		{
			if(f[i][j]==0) f[i][j]=1;
			else f[i][j]=0;
		}
	}
	for(int i=1;i<=2001;i++)
	{
		for(int j=1;j<=i;j++)
		{
			ch[i][j]=ch[i][j-1]+f[i][j];
		}
	}
	for(int i=1;i<=2001;i++)
	{
		for(int j=i;j<=2001;j++)
		{
			cs[j][i]=cs[j-1][i]+f[j][i];
		}
	}
	for(int i=1;i<=2001;i++)
	{
		for(int j=1;j<=i;j++)
		{
			sum[i][j]=sum[i-1][j-1]+cs[i][j]+ch[i][j]-f[i][j];
		}
	}
	while(t--)
	{
		scanf("%d%d",&n,&m);
		if(n==0||m==0) cout<<0<<endl;
		else printf("%lld\n",sum[n][min(n,m)]);
	}
	return 0;
}
posted @ 2020-03-15 18:07  童话镇里的星河  阅读(94)  评论(0编辑  收藏  举报