【矩阵快速幂专题】Codeforces 450B. Jzzhu and Sequences

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qian2213762498/article/details/82181770

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/qian2213762498/article/details/82181770