ZOJ 3690 矩阵快速幂乘

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3690
题意:有n个人站在一排,另外有m个号码,每个人都选其中的一个号码,但是有一个条件是,如果两个相邻人选了相同的号码,那么这个号码要大于k;问一共有多少种不同的选法
思路:
  1   2   3   4 .......表示站第n的人
               |-k...........
      |--(k-1)-|
      |        |(m-k)........
 |--k-|       |--k ..........
 |    |--(m-k)|
 |            |(m-k).........
 |
 |            |-(k-1)........
 |      |--k--|
 |(m-k)-|     |-(m-k).......
        |
        |     |--k..........
        |(m-k)|
              |(m-k).........
答案肯定是这些一条条链乘起来再相加了,问题是怎么算呢?
可以看到每个k后面都是(k-1),(m-k),每个(m-k)和(k-1)后面都是(m-k)
第一次时令a=m-k, b=k; f[2] = (a+b)*(m-k) + (a*k+b*(k-1)) ;
第二次时令a=(a+b)*(m-k), b=(a*k+b*(k-1)); 则f[3]= (a+b)*(m-k) + (a*k+b*(k-1))
第三次........
发现了没,这些式子是一样的,这是不是又想到了两个2*2的矩阵乘法呢?
              (m-k)   k|    |(m-k)     k |
     f[2]=    |      |  *  |        |
              |0     0|    |(m-k)  (k-1)|

不难推出:


              (m-k)   k|    |(m-k)     k | ^(n-1)
     f[n]=    |      |   * |        |
              |0     0|   |(m-k)  (k-1)|

接下来用矩阵幂乘就可以了!!


#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<iomanip>

using namespace std;
typedef long long ll;
const int mod=1000000007;

struct Matrix {
    ll  x, y;
    ll  z, w;
} R,M;
Matrix multi( Matrix A, Matrix B ) {
    Matrix Z;
    Z.x = (A.x*B.x+A.y*B.z)%mod;
    Z.y = (A.x*B.y+A.y*B.w)%mod;
    Z.z = (A.z*B.x+A.w*B.z)%mod;
    Z.w = (A.z*B.y+A.w*B.w)%mod;
    return Z;
}

void calc(int n){ /// M = R^n;
    M=R;
    while(n){
        if(n&1)
            M=multi(M,R);
        n>>=1;
        R=multi(R,R);
    }
}

int main() {
    int n,m,k;
    while(cin>>n>>m>>k) {
        R.x = R.z = m-k;
        R.y = k;
        R.w = k-1;
        calc( n-2 );
        ll ans =( (m-k)*M.x + k*M.z + (m-k)*M.y + k*M.w )%mod ;
        cout<< ans <<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值