题目链接:http://codeforces.com/problemset/problem/450/B
B. Jzzhu and Sequences
Jzzhu has invented a kind of sequences, they meet the following property:
You are given x and y, please calculate fn modulo 1000000007 (109 + 7).
Input
The first line contains two integers x and y (|x|, |y| ≤ 109). The second line contains a single integer n (1 ≤ n ≤ 2·109).
Output
Output a single integer representing fn modulo 1000000007 (109 + 7).
Examples
input
2 3
3
output
1
input
0 -1
2
output
1000000006
Note
In the first sample, f2 = f1 + f3, 3 = 2 + f3, f3 = 1.
In the second sample, f2 = - 1; - 1 modulo (109 + 7) equals (109 + 6).
思路
矩阵快速幂求解递推式,刚开始构造的矩阵都是3*3的,思路极其简单,但是总是卡在第51个测试点过不去。
于是:换个角度,把矩阵构造为2*2,于是就AC了。
以下代码卡在第51个测试点:(主要是3*3考虑的)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const ll nmax=3;
const ll MOD=1e9+7;
#define mod(x) ((x)%MOD)
int n;
struct mat{
ll m[nmax][nmax];
}unit;
//A*B^(n-2)=C //C矩阵的首项即为f(n)
mat operator *(mat a,mat b){
mat ret;
ll x;
for(ll i=0;i<nmax;i++){//3*3
for(ll j=0;j<nmax;j++){
x=0;
for(ll k=0;k<nmax;k++){
x+=mod((ll)a.m[i][k]*b.m[k][j]);
}
ret.m[i][j]=mod(x);
}
}
return ret;
}
void init_unit(){
for(ll i=0;i<nmax;i++){
unit.m[i][i]=1;
}
return;
}
mat pow_mat(mat a,ll n){//求矩阵a的n次幂
mat ret=unit;
while(n){
if(n&1) ret=ret*a;
a=a*a;
n>>=1;
}
return ret;
}
int main(int argc, char** argv) {
ll n;
ll a1,a2,a3;
init_unit();
while(scanf("%lld%lld",&a1,&a2)!=EOF){//需要求矩阵B的n-2次幂
scanf("%I64d",&n);
a3=a2-a1;
if(n==1ll) printf("%lld\n",(a1+MOD)%MOD);//printf("%lld\n",a1<0?mod(a1+MOD):mod(a1));
else if(n==2ll) printf("%lld\n",(a2+MOD)%MOD);//printf("%lld\n",a2<0?mod(a2+MOD):mod(a2));
else if(n==3ll) printf("%lld\n",(a3+MOD)%MOD);//printf("%lld\n",a3<0?mod(a3+MOD):mod(a3));
else{
mat a,b;
b.m[0][0]=1;b.m[0][1]=1;b.m[0][2]=0;
b.m[1][0]=-1;b.m[1][1]=0;b.m[1][2]=1;
b.m[2][0]=0;b.m[2][1]=0;b.m[2][2]=0;
a.m[0][0]=a3;a.m[0][1]=a2;a.m[0][2]=a1;
b=pow_mat(b,n-3);
a=a*b;
if(a.m[0][0]<0){
a.m[0][0]+=MOD;
}
printf("%lld\n",a.m[0][0]);
//cout<<mod(a.m[0][0])<<endl;
}
}
return 0;
}
AC Code(以下是2*2做法)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const ll nmax=2;
const ll MOD=1e9+7;
#define mod(x) ((x)%MOD)
int n;
struct mat{
ll m[nmax][nmax];
}unit;
//A*B^(n-2)=C //C矩阵的首项即为f(n)
mat operator *(mat a,mat b){
mat ret;
ll x;
for(ll i=0;i<nmax;i++){//2*2
for(ll j=0;j<nmax;j++){
x=0;
for(ll k=0;k<nmax;k++){
x+=mod((ll)a.m[i][k]*b.m[k][j]);
}
ret.m[i][j]=mod(x);
}
}
return ret;
}
void init_unit(){
for(ll i=0;i<nmax;i++){
unit.m[i][i]=1;
}
return;
}
mat pow_mat(mat a,ll n){//求矩阵a的n次幂
mat ret=unit;
while(n){
if(n&1) ret=ret*a;
a=a*a;
n>>=1;
}
return ret;
}
int main(int argc, char** argv) {
ll n;
ll a1,a2,a3;
init_unit();
while(scanf("%lld%lld",&a1,&a2)!=EOF){//需要求矩阵B的n-2次幂
scanf("%lld",&n);
if(n==1) printf("%lld\n",a1<0?mod(a1+MOD):mod(a1));//printf("%lld\n",(a1+MOD)%MOD);
else if(n==2) printf("%lld\n",a2<0?mod(a2+MOD):mod(a2));//printf("%lld\n",(a2+MOD)%MOD);
else{
mat a,b;
b.m[0][0]=1;b.m[0][1]=1;
b.m[1][0]=-1;b.m[1][1]=0;
a.m[0][0]=a2;a.m[0][1]=a1;
b=pow_mat(b,n-2);
a=a*b;
if(a.m[0][0]<0){
a.m[0][0]+=MOD;
}
printf("%lld\n",(a.m[0][0]+MOD)%MOD);
}
}
return 0;
}