zoukankan      html  css  js  c++  java
  • bzoj 4737: 组合数问题

    Description

     组合数C(n,m)表示的是从n个物品中选出m个物品的方案数。举个例子,从(1,2,3)三个物品中选择两个物品可以有(

    1,2),(1,3),(2,3)这三种选择方法。根据组合数的定义,我们可以给出计算组合数C(n,m)的一般公式:
    C(n,m)=n!/m!*(n?m)!
    其中n!=1×2×?×n。(额外的,当n=0时,n!=1)
    小葱想知道如果给定n,m和k,对于所有的0≤i≤n,0≤j≤min(i,m)有多少对(i,j)满足C(i,j)是k的倍数。

    Input

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

    Output

     t行,每行一个整数代表所有的0≤i≤n,0≤j≤min(i,m)中有多少对(i,j))满足C(i,j)是k的倍数

    答案对10^9+7取模。

    由lucas定理的推论,C(i,j)不是k的倍数当且仅当k进制下i的每一位分别>=j

    先补上前导零使n,m位数相同从高位到低位进行数位dp,f[i][0/1][0/1]表示当前已决策高于第i位的部分,已决策部分是否与n,m相等,满足条件的方案数。

    #include<cstdio>
    #include<cstring>
    const int P=1000000007;
    typedef long long i64;
    int T,k,ns[107],ms[107],f[107][2][2];
    i64 n,m;
    int min(int a,int b){return a<b?a:b;}
    int max(int a,int b){return a>b?a:b;}
    i64 S(i64 x){return x%=P,x*(x+1)/2%P;}
    i64 cal(i64 a,i64 b){
        if(a<b)b=a;
        return (S(a)-S(a-b))%P;
    }
    i64 s[107][107];
    int main(){
        scanf("%d%d",&T,&k);
        for(int i=0;i<=k;++i)
        for(int j=0;j<=k;++j)s[i][j]=cal(i,j);
        for(;T;--T){
            scanf("%lld%lld",&n,&m);
            if(n<m)m=n;
            int ans=cal(n+1,m+1);
            int np=0,mp=0;
            while(n)ns[++np]=n%k,n/=k;
            while(m)ms[++mp]=m%k,m/=k;
            while(mp<np)ms[++mp]=0;
            memset(f,0,sizeof(f));
            f[np][1][1]=1;
            for(int i=np;i;--i){
                int(*F)[2]=f[i],(*G)[2]=f[i-1];
                int vn=ns[i],vm=ms[i];
                G[1][1]=F[1][1]*(vn>=vm);
                G[1][0]=(F[1][0]*i64(vn+1)+F[1][1]*(i64)min(vn+1,vm))%P;
                G[0][1]=(F[0][1]*i64(k-vm)+F[1][1]*(i64)max(vn-vm,0))%P;
                G[0][0]=(F[0][0]*s[k][k]+F[0][1]*s[k][vm]+F[1][0]*s[vn][k]+F[1][1]*s[vn][vm])%P;
            }
            for(int a=0;a<2;++a)
            for(int b=0;b<2;++b)
            ans=(ans-f[0][a][b])%P;
            printf("%d
    ",(ans+P)%P);
        }
        return 0;
    }
  • 相关阅读:
    构造代码块/局部代码块/静态代码块
    经典设计模式之:单例设计模式
    JS对表单的操作
    单例模式详解:懒汉式与饿汉式
    win10获取超级管理员权限脚本实现
    CIA 读书笔记
    Google Code Jam 2014 资格赛:Problem D. Deceitful War
    Google Code Jam 2014 资格赛:Problem C. Minesweeper Master
    Google Code Jam 2014 资格赛:Problem B. Cookie Clicker Alpha
    Google Code Jam 资格赛: Problem A. Magic Trick
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6767097.html
Copyright © 2011-2022 走看看