您的位置:首页 > 其它

ZOJ 3690 矩阵快速幂乘

2013-04-14 01:02 27 查看
题目链接: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
= |    | * |      |

|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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: