ZOJ3690Choosing number

来源:互联网 发布:php图片用什么打开 编辑:程序博客网 时间:2024/06/05 02:21

题意就是:

       有n个人,每个人可以从m个数中选取其中的一个数,而且如果两个相邻的数相同,则这个数不能超过k,问这样的数一共有多少种选择,结果取模。

思路:

       我们用 f[i]表示第i个位置大于k的种数,用g[i]表示第i个数小于等于k的种数。则最终的答案就是(f[i]+g[i])%mod。

       f[i] =f[i-1]*(m-k)+g[i-1]*(m-k);

       g[i]=f[i-1]*k+g[i-1]*(k-1);

因为n的值很大,所以我们得用矩阵快速幂来求解。

矩阵:      k-1  m-k

                 k     m-k

初始矩阵为:

                 0      1

                 0      0

代码:

#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
#define LL long long
#define MOD 1000000007
struct node {
    LL val[2][2];
};
node Init;
node ans;
LL n,m,k;
void init() {
    Init.val[0][0] = 0;
    Init.val[0][1] = 1;
    Init.val[1][0] = 0;
    Init.val[1][1] = 0;


    ans.val[0][0] = k - 1;
    ans.val[0][1] = m - k;
    ans.val[1][0] = k;
    ans.val[1][1] = m - k;
}


node Mul(node a,node b) {
    node tmp;
    for(int i = 0; i < 2; i ++) {
        for(int j = 0; j < 2; j ++) {
            tmp.val[i][j] = 0;
            for(int k = 0; k < 2; k ++) {
                tmp.val[i][j] += (a.val[i][k] * b.val[k][j]) % MOD;
                tmp.val[i][j] %= MOD;
            }
        }
    }
    return tmp;
}


void solve() {
    init();
    while(n) {
        if(n & 1) {
            Init = Mul(Init,ans);
        }
        ans = Mul(ans,ans);
        n >>= 1;
    }
    LL ANS = 0;
    ANS = (Init.val[0][0] + Init.val[0][1]) % MOD;
    cout<<ANS<<endl;
}


int main() {
    while(cin>>n>>m>>k) {
            solve();
    }
    return 0;
}


0 0
原创粉丝点击