zoukankan      html  css  js  c++  java
  • 【NOIP2016】组合数问题 题解(组合数学+递推)

    题目链接

    题目大意:给定$n,m,k$,求满足$k|C_i^j$的$C_i^j$的个数。$(0leq ileq n,1leq jleq min(i,m))$。

    ----------------

    关于组合数的递推不难想到。简略证明一下。

    证明:$C_i^j=C_{i-1}^j+C_{i-1}^{j-1}$。

    $  C_{i-1}^j+C_{i-1}^{j-1}$

    $=frac{(i-1)!}{j!(i-j-1)!}+frac{(i-1)!}{(j-1)!(i-j)!}$

    $=frac{(i-1)!*(i-j)}{j!*(i-j)!}+frac{(i-1)!*j}{j!(i-j)!}$

    $=frac{(i-1)!*(j+i-j)}{j!*(i-j)!}$

    $=frac{i!}{j!(i-j)!}$

    $=C_i^j$

    递推出的结果再$mod k$就可以拿到90分了,大部分人考场上就可以过了,有时间可以再深究一下。

    满分还要有一个递推式:$ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1]$。打表可以得到。

    注意边界。时间复杂度$O(n^2)$。$O(1)$查询。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    long long c[2005][2005],ans[2005][2005];
    int k,n,m,t;
    int main()
    {
        scanf("%d%d",&t,&k);
        c[0][0]=c[1][0]=1;c[1][1]=1;
        for (int i=2;i<=2000;i++)
        {
            c[i][0]=1;
            for (int j=1;j<=i;j++) 
            {
                c[i][j]=(c[i-1][j-1]+c[i-1][j])%k;
                ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1];
                if (!c[i][j]) ans[i][j]++;
            }
            ans[i][i+1]=ans[i][i];
        }
        while(t--)
        {
            scanf("%d%d",&n,&m);
            if (m>n)printf("%lld
    ",ans[n][n]);
            else printf("%lld
    ",ans[n][m]);
        }
        return 0;
    } 
  • 相关阅读:
    内置函数——filter和map
    递归函数
    内置函数和匿名函数
    迭代器和生成器
    装饰器函数
    函数进阶
    COGS 2533. [HZOI 2016]小鱼之美
    COGS 2532. [HZOI 2016]树之美 树形dp
    COGS2531. [HZOI 2016]函数的美 打表+欧拉函数
    bzoj1303: [CQOI2009]中位数图
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12925718.html
Copyright © 2011-2022 走看看