Live2d Test Env

ZOJ - 3216:Compositions (DP&矩阵乘法&快速幂)

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\n",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\n",ans.mp[1][1]);
    }
    return 0;
}

 

posted @ 2018-12-27 13:13  nimphy  阅读(243)  评论(0编辑  收藏  举报