zoukankan      html  css  js  c++  java
  • ZOJ

    We consider problems concerning the number of ways in which a number can be written as a sum. If the order of the terms in the sum is taken into account the sum is called a composition and the number of compositions of n is denoted by c(n). Thus, the compositions of 3 are

    • 3 = 3
    • 3 = 1 + 2
    • 3 = 2 + 1
    • 3 = 1 + 1 + 1

    So that c(3) = 4.

    Suppose we denote by c(n, k) the number of compositions of n with all summands at least k. Thus, the compositions of 3 with all summands at least 2 are

    • 3 = 3

    The other three compositions of 3 all have summand 1, which is less than 2. So that c(3, 2) = 1.

    Input

    The first line of the input is an integer t (t <= 30), indicate the number of cases.

    For each case, there is one line consisting of two integers n k (1 <= n <= 109, 1 <= k <= 30).

    Output

    Output c(n, k) modulo 109 + 7.

    Sample Input

    2
    3 1
    3 2
    

    Sample Output

    4
    1
    

    题意:给定N,K,问N可以由多少个不小于K的数组合起来。

    思路:当K=1时,就是隔板法,组合数之和,答案是2^(N-1) ;当K>1;可以得到方程dp[i]=dp[i-1]+dp[i-k];

    我们用dpi表示和为i有多少种方案,那么考虑最后一个数,如果最后一个数=k,那么其方案数=dp[i-k];如果>k,那么其方案数=dp[i-1]; 想到这里就知道用矩阵乘法来做了。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int Mod=1e9+7;
    int L;
    int qpow(int a,int x)
    {
        int res=1; while(x){
            if(x&1) res=1LL*res*a%Mod;
            a=1LL*a*a%Mod; x>>=1;
        } return res;
    }
    struct mat
    {
        int mp[31][31];
        mat(){memset(mp,0,sizeof(mp));}
        mat friend operator*(mat a,mat b){
            mat res;
            rep(k,1,L)
             rep(i,1,L)
              rep(j,1,L)
             (res.mp[i][j]+=1LL*a.mp[i][k]*b.mp[k][j]%Mod)%=Mod;
            return res;
        }
        mat friend operator^(mat a,int x){
            mat res; rep(i,1,L) res.mp[i][i]=1;
            while(x){
                if(x&1) res=res*a;
                a=a*a; x>>=1;
            } return res;
        }
    };
    int main()
    {
        int T,N,K;
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&N,&K);
            if(N<K) {puts("0"); continue;}
            if(K==1){ printf("%d
    ",qpow(2,N-1)); continue;}
            mat ans,base; L=K;
            ans.mp[1][1]=1;
            base.mp[1][1]=base.mp[1][K]=1;
            rep(i,2,K) base.mp[i][i-1]=1;
            ans=(base^(N-K))*ans;
            printf("%d
    ",ans.mp[1][1]);
        }
        return 0;
    }
  • 相关阅读:
    Sqlite基础(一)
    个人作业冲刺(四)
    安卓用户名密码操作及虚拟机问题
    安卓之界面跳转
    个人作业冲刺(三)
    个人作业冲刺(二)
    个人作业冲刺(一)
    Android studio RatingBar(星级评分条)
    阅读笔记——《构建之法》4
    Android studio GridLayout(网格布局)
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10184405.html
Copyright © 2011-2022 走看看