2016 组合数问题

组合数问题

题面

在这里插入图片描述
对,就是这样这样的一道题,卡了博主好多天,emmmm,反正最后是看题解ac的……(是吧,我也感觉自己好弱)
首先,上一份自己看的题解,强烈推荐!!!
https://www.luogu.org/problemnew/solution/P2822

——————————————————————————————
然后,下面是我们的正文
我们是可以直接用公式暴力的,但是你可曾考虑到了数据范围…………(博主只拿了20分)
这道题其实有很多细节,可以看出一丢丢思路(当然,一开始我也没看出来,之后,打完代码之后再看了好几遍题)
1.
在这里插入图片 描述
在这个范围中,可以看出 j 的范围是肯定要小于 i 的,(这里先不要考虑m的范围,m的范围在之后会有用),那么,我们在举几个例子,
当i=0时,j=0;
当i=1时,j=0,1;
当i=2时,j=0,1,2;
……
这时候,我们可以看出这貌似是个三角形(我觉得思维迁徙能力比较强的,就应该已经想到了杨辉三角(因为组合数是和杨辉三角有关系的))
思维迁徙能力不好的,不要怕,因为博主就是……
那么思考一下,为什么上面博主说和杨辉三角有关系呢,这个时候就应该想到打表了吧,不知道为什么有关系,几个数据证实一下就可以了(用公式啊)自己实现
之后,我们就可以发现数据是这样的1 11 121 1331 14641 …,这不就是杨辉三角!!!当发现这个的时候,有思路了吧,暴力啊,可是你在看一眼数据范围……,(博主的暴力只拿了55分……)
之后再考虑其他的方法,在这里引入一个新的概念“前缀和
不懂的找度娘,这里只说一个公式,s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
上加左减左上
然后看一下代码

	#include<bits/stdc++.h>
	using namespace std;
	int c[2100][2100];
	int s[2100][2100];//求前缀和的数组
	int t,k;
	int n,m;
	void zhs()
	{
	    c[0][0]=c[1][0]=c[1][1]=1;
	    for(int j=2;j<=2010;j++)
	    {
	        c[j][0]=1;
	        for(int l=1;l<=j;l++)
	        {
	            s[j][l]=s[j-1][l]+s[j][l-1]-s[j-1][l-1];//就是上面的公式
	            c[j][l]=(c[j-1][l-1]%k+c[j-1][l]%k)%k;
	            if(c[j][l]%k==0)	s[j][l]+=1;
	        }	
	        s[j][j+1]=s[j][j];//敲黑板,划重点,这个必须有!!详见下面的解释
	    }			
	}
	int main()
	{
	    //freopen("1.in","r",stdin);
	    scanf("%d%d",&t,&k);
	    zhs();
	    for(int i=1;i<=t;i++)
	    {
	        scanf("%d%d",&n,&m);
	        if(m>n)	cout<<s[n][n]<<endl;
	        else 	cout<<s[n][m]<<endl;
	    }
	    return 0;
	}

注:s[j][j+1]=s[j][j];
假使没有这一句,我们看一下输出(根据第二个样例)
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 3 0 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 4 0 6 0 4 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 5 2 10 3 10 4 5 *4 1 ** 0 0 0 0 0 0 0 0 0 0
0 1 1 6 3 15 5 20 7 15 7 6 3 1 0 0 0 0 0 0 0 0
0 1 1 7 3 21 6 35 9 35 9 21 **5 7 * 2 1 0 0 0 0 0 0
0 1 1 8 3 28 6 56 10 70 10 56 6 28 ***3 8 *** 1 1 0 0 0 0
0 1 1 9 3 36 6 84 10 126 10 126 6 84 3 36 1 9 0 1 0 0
0 1 2 10 5 45 9 120 14 210 14 252 11 210 9 120 8 45 8 10 8 1
只有黑体的地方就是s[j][j+1]的地方,但是,我们可以明显的发现到不对,这个数据不对……怎么办??
这就是上面的解决的妙处了,传递,将 有下划线的数字传递给黑体数字,这样!!!!不就解决了,对吧

猜你喜欢

转载自blog.csdn.net/qq_43093454/article/details/83829569