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;
    } 
  • 相关阅读:
    Your First ASP.NET 5 Application on a Mac
    vnextcn
    基于微服务的软件架构模式
    数组链表下标指针map list
    十一、从头到尾彻底解析Hash 表算法
    failed to create hive metastore database tables
    VSCode 常用插件
    HTML中块级行级元素小分类
    WEB前端程序员需要的网站整理
    UI1_HTTP下载
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12925718.html
Copyright © 2011-2022 走看看