zoj3690--Choosing number(dp,矩阵快速幂)

 Choosing number
Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu

Description

There are n people standing in a row. And There are m numbers, 1.2...m. Every one should choose a number. But if two persons standing adjacent to each other choose the same number, the number shouldn't equal or less than k. Apart from this rule, there are no more limiting conditions.

And you need to calculate how many ways they can choose the numbers obeying the rule.

Input

There are multiple test cases. Each case contain a line, containing three integer n (2 ≤ n ≤ 108), m (2 ≤ m ≤ 30000), k(0 ≤ k ≤ m).

Output

One line for each case. The number of ways module 1000000007.

Sample Input

4 4 1

Sample Output

216

题意:n个人每个人在m个数中选一个,要求相邻的人如果数字相同,那么数字要大于k,问有多少种选法

dp[i][0] 代表有i个人时 且最后一个人选的数小于等于k的种数

dp[i][0] 代表有i个人时 且最后一个人选的数大于k的种数

用矩阵快速幂的优化和http://blog.csdn.net/winddreams/article/details/42805891相同


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define LL long long
#define MOD 1000000007
struct node
{
    LL a[5][5] ;
    int n ;
};
node mul(node p,node q)
{
    int i , j , k ;
    node s ;
    s.n = p.n ;
    for(i = 0 ; i < p.n ; i++)
        for(j = 0 ; j < p.n ; j++)
        {
            s.a[i][j] = 0 ;
            for(k = 0; k < p.n ; k++)
                s.a[i][j] = ( s.a[i][j] + p.a[i][k]*q.a[k][j] ) % MOD ;
        }
    return s ;
}
node pow(node p,int k)
{
    if( k == 1 )
        return p ;
    node s = pow(p,k/2) ;
    s = mul(s,s) ;
    if( k%2 )
        s = mul(s,p) ;
    return s ;
}
int main()
{
    LL n , m ,  k , ans ;
    int i , j ;
    node p , s ;
    while( scanf("%lld %lld %lld", &n, &m, &k) != EOF )
    {
        ans = 0 ;
        p.n = 2;
        p.a[0][0] = k-1 ; p.a[0][1] = k ;
        p.a[1][0] = m-k ; p.a[1][1] = m-k ;
        s = pow(p,n-1) ;
        ans = ( ans + s.a[0][0]*k + s.a[1][0]*k ) % MOD ;
        ans = ( ans + s.a[0][1]*(m-k) + s.a[1][1]*(m-k) ) % MOD ;
        printf("%lld\n", ans) ;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值