zoukankan      html  css  js  c++  java
  • 【Luogu P2282】【JZOJ 4906】【NOIP2016提高组复赛】组合数问题 题解

    【Luogu P2282】【JZOJ 4906】【NOIP2016提高组复赛】组合数问题 题解


    题面入口--->点这里


    题解&&思路

    题意简析

     题面上已经描述的很清楚了,就是求一些组合数中有几个为k的倍数。

    暴力做法

     对于每一个询问n,m,直接按照题意枚举i,j求出C(i,j)%k的值,统计答案。
     考虑组合数的求法,就我所知有3种:

    1. 根据组合数的计算公式直接计算。复杂度(O(n)),但是数很大的时候没法做。
    2. 利用组合数递推式进行计算,这个递推式就是(C_n^m=C_{n-1}^m+C_{n-1}^{m-1}),也就是杨辉三角求组合数。
    3. 针对方法1的优化,利用逆元求(C_n^m mod k)
       但是方法1和方法3都不是我们关注的重点,因为枚举n,m的复杂度为(O(tnm)),必定超时。

    正解思路

     那么有名到小学生都知道的杨辉三角到底能对这题起到什么帮助呢?如果使用杨辉三角,就能在(O(nm))预处理后(O(1))回答所有(C_n^m mod k)的问题。观察这道题,k是给定的,于是我们可以预处理每个组合数mod k的值,若其为0,说明这个组合数是k的倍数。
     但是还是要(O(nm))枚举,解决不了问题,怎么办呢。
     考虑这样一些式子:
    n=1,m=1时ans=(C_1^1)
    n=2,m=1时ans=(C_1^1+C_2^1)
    n=2,m=2时ans=(C_1^1+C_2^1+C_2^2)
    ...
     每个答案都包含了前面的答案!那么这个包含的递推式是?我们设f[i][j]为n=i,m=j时的答案,递推式就是:

    [f_i_,_j=f_{i-1}_,_j+f_i_,_{j-1}-f_{i-1}_,_{j-1} ]

     其实就是前缀和。当(C_i^j mod k = 0)时f[i][j]要+1。于是就能在(O(nm))预处理下(O(1))回答询问了。
     注意一下细节问题,代码中有体现。

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    
    const int N = 2007;
    
    int t, k, n, m;
    long long f[N][N], sum[N][N]; //不开long long翻车
    
    int main()
    {
    	freopen("problem.in", "r", stdin); //无视文件操作
    	freopen("problem.out", "w", stdout);
    
    	scanf("%d%d", &t, &k);
    	f[0][0] = 1;
    	for (int i = 1; i <= 2000; i++)
    	{
    		f[i][0] = 1; //杨辉三角的第0列也就是左边一列全为1,组合数定义C(n,m)=1 (n≠0,m=0)
    		for (int j = 1; j <= i; j++)
    		{
    			f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % k; //边递推边取模,因为我们只关心C(n,m)%k的值
    			if (f[i][j] == 0) sum[i][j]++; //f[i][j] % k == 0说明C(i,j)是k的倍数
    		}
    	}
    	for (int i = 1; i <= 2000; i++)
    		for (int j = 1; j <= i; j++)
    			if (i == j) sum[i][j] += sum[i][j - 1]; //特判,不加会错
    			else sum[i][j] += sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1]; //前缀和统计答案
    	while (t--)
    	{
    		scanf("%d%d", &n, &m);
    		if (m > n) m = n; //如上文所述
    		printf("%lld
    ", sum[n][m]);
    	}
    
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    大数据产品对比
    3人3天3桶水9个人9天用几桶水
    skatebroads
    手机全面屏屏占比93%以上解决方案
    POC
    公司网站 解决方案 案例
    GBT 31000-2015 社会治安综合治理基础数据规范 数据项 编码
    GBT 33200-2016 社会治安综合治理 综治中心建设与管理规范 GBT 31000-2015 社会治安综合治理基础数据规范
    大数据 交警 户外广告设施管理监管系统平台高空坠物智慧社区城市城管警务
    破解爱奇艺腾讯优酷会员限制
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/8343986.html
Copyright © 2011-2022 走看看