• NOIP201608组合数问题


    【问题描述】

    组合数Cmn表示的是从n个物品中选出m个物品的方案数。举个例子,从(1,2,3)三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法。根据组合数的定 义,我们可以给出计算组合数的一般公式:
    Cnm=(n!m!)/(n−m)!
    其中n! = 1 × 2 × · · · × n
    小葱想知道如果给定n,mk,对于所有的0 <= i <= n,0 <= j <= min(i,m)有多少对(i,j)满足Cjik的倍数。

    【输入格式】

    第一行有两个整数t,k,其中t代表该测试点总共有多少组测试数据,k的意义见 【问题描述】。
    接下来t行每行两个整数n,m,其中n,m的意义见【问题描述】。

    【输出格式】

    t行,每行一个整数代表答案。

    【样例输入】

    【样例一】

    1 2
    3 3

    【样例二】

    1

    【样例输出】

    【样例一】

    2 5
    4 5
    6 7

    【样例二】

    0
    7

    【数据范围】

    1<=n,m<=2000,1<=t<=10000,1<=k<=21

    【题解】

    组合数求和公式Cnm=C(n-1)(m-1)+C(n-1)m
    直接先预处理出所有数是不是k的倍数,然后再用二维前缀和就可以搞定了

    【代码】

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define ll long long
    #define f(i,n) for(int i=1;i<=(n);i++)
    #define MN 2010
    #define N 2000
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while( isdigit(c)){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    int ans[MN][MN],dp[MN][MN];
    int t,k,n,m;
    int main()
    {
    	t=read();k=read();
    	f(i,N)dp[i][0]=dp[0][i]=1;
    	f(i,N)for(int j=1;j<=i;j++)
    	{
    		dp[i][j]=(dp[i-1][j-1]+dp[i-1][j])%k;
    		if(!dp[i][j])ans[i][j]=1;
    	}
    	f(i,N)f(j,N)ans[i][j]+=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];
    	while(t--)
    	{
    		n=read();m=read();
    		printf("%d
    ",ans[n][m]);
    	}
    }
    
  • 相关阅读:
    将cvs迁移到svn
    wincvs,cvs,svn
    Open Source Camp 北京 2008技术交流盛会 感悟
    21,22,23,24日外出纪要
    10.31,11.1外出纪要
    虚拟经济区一行有感
    29,30号活动预告
    ror 2.1.2migration
    netbeans 6.5 release
    [转载]ruby on rails 每周精选二
  • 原文地址:https://www.cnblogs.com/qwerfcxs/p/7814639.html
Copyright © 2020-2023  润新知