这是关于斐波拉切的经典操作
POJ3070
这是关于斐波拉切数列用矩阵表示的最基本的题,正如题目描述的那样,f[i]=A^i.a[0][1],在这儿A为固定矩阵
| 1 1 |
A = | |
| 1 0 |
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<climits>
#define maxn 10000
#define mod 10000
using namespace std;
struct matrix
{
int a[2][2];
void clear()
{
memset(a,0,sizeof(a));
}
void init()
{
a[0][0]=1;
a[0][1]=1;
a[1][0]=1;
a[1][1]=0;
}
matrix operator +(const matrix &b)const
{
matrix c;
c.clear();
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
c.a[i][j]=a[i][j]+b.a[i][j];
}
}
return c;
}
matrix operator *(const matrix b)const
{
matrix c;
c.clear();
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
for(int k=0; k<2; k++)
{
c.a[i][j]+=a[i][k]*b.a[k][j];
}
c.a[i][j]=c.a[i][j]%mod;
}
}
return c;
}
};
matrix pow(matrix a,int b)
{
matrix per;
per.init();
while(b)
{
if(b&1)
{
per=per*a;
}
a=a*a;
b>>=1;
}
return per;
}
int main()
{
//freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
int n;
matrix a,ans;
a.init();
while(cin>>n)
{
if(n==-1)break;
if(n==0){puts("0");continue;}
else
{
ans=pow(a,n-1);
cout<<(ans.a[0][1])%mod<<endl;
}
}
return 0;
}
HDU3306
/*************************
http://acm.hdu.edu.cn/showproblem.php?pid=3306
题意:Fibonacci : A(0) = 1 , A(1) = 1 , A(N) = X * A(N - 1) + Y * A(N - 2) (N >= 2).
计算A(0)^2+……A(N)^2
思路:构造矩阵 矩阵如下
|1 x^2 y^2 2xy| | S(N-1) | | S(N) |
|0 x^2 y^2 2xy| * | A(N-1)^2 | = | A(N)^2 |
|0 1 0 0 | | A(N-2)^2 | | A(N-1)^2|
|0 x 0 y | |A(N-1)A(N-2)| |A(N)A(N-1)|
*************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define mod 10007
using namespace std;
int t,x,y;
struct matrix
{
int n,m;
int a[5][5];
void clear()
{
m=n=0;
memset(a,0,sizeof(a));
}
matrix operator +(const matrix &b)const
{
matrix c;
c.clear();
c.n=n,c.m=m;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
c.a[i][j]=(a[i][j]+b.a[i][j])%mod;
}
}
return c;
}
matrix operator *(const matrix &b)const
{
matrix c;
c.clear();
c.n=n,c.m=b.m;
for(int i=0; i<n; i++)
{
for(int j=0; j<b.m; j++)
{
for(int k=0; k<m; k++)
{
c.a[i][j]+=a[i][k]*b.a[k][j];
}
c.a[i][j]%=mod;
}
}
return c;
}
};
matrix pow(matrix a,int b)
{
matrix ans;
ans.clear();
ans.n=ans.m=a.n;
for(int i=0; i<a.n; i++)
{
ans.a[i][i]=1;
}
while(b)
{
if(b&1)
{
ans=ans*a;
}
a=a*a;
b>>=1;
}
return ans;
}
matrix a,b;
__int64 ans;
int main()
{
while(~scanf("%d%d%d",&t,&x,&y))
{
x%=mod,y%=mod;
if(t==0||t==1)
{
printf("1\n");
continue;
}
a.clear();
a.n=a.m=4;
a.a[0][0]=a.a[2][1]=1;
a.a[0][1]=a.a[1][1]=x*x%mod;
a.a[0][2]=a.a[1][2]=y*y%mod;
a.a[0][3]=a.a[1][3]=2*x*y%mod;
a.a[3][1]=x;
a.a[3][3]=y;
b.clear();
b.n=4,b.m=1;
b.a[0][0]=2;
b.a[1][0]=1;
b.a[2][0]=1;
b.a[3][0]=1;
a=pow(a,t-1);
a=a*b;
ans=0;
for(int i=0;i<4;i++)
{
ans+=a.a[0][i];
}
printf("%d\n",ans%mod);
}
return 0;
}
HDU4549
/*************************
http://acm.hdu.edu.cn/showproblem.php?pid=4549
题意:
F[0] = a
F[1] = b
F[n] = F[n-1] * F[n-2] ( n > 1 )计算F[n]%1000000007
思路:矩阵构造+欧拉函数+整数快速幂+矩阵快速幂
通过对表达式的求解可以得到F[]的最终形式是对ab的斐波拉切数的乘积,
即F[i]=a^f[i-1]*b^f[i]
在这儿f[]表示最基本的菲波拉契数列,而关于菲波拉契数可以通过矩阵构造得到
此后可以通过整数快速幂来求解答案,只是注意矩阵乘法会溢出,即使%mod也会,因此要用到欧拉函数来优化
在欧拉函数中有这么一个定理
A^B%C=A^(B%phi(C)+phi(C))%C B>=phi(C)
在这儿phi表示欧拉函数,而mod为素数,因此phi(C)=mod-1
这题贡献了无数次WA---主要数关于mod的问题
*************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define mod 1000000007
using namespace std;
__int64 x,y,t;
struct matrix
{
int n,m;
__int64 a[5][5];
void clear()
{
m=n=0;
memset(a,0,sizeof(a));
}
matrix operator +(const matrix &b)const
{
matrix c;
c.clear();
c.n=n,c.m=m;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
c.a[i][j]=(a[i][j]+b.a[i][j])%(mod-1);
}
}
return c;
}
matrix operator *(const matrix &b)const
{
matrix c;
c.clear();
c.n=n,c.m=b.m;
for(int i=0; i<n; i++)
{
for(int j=0; j<b.m; j++)
{
for(int k=0; k<m; k++)
{
c.a[i][j]+=a[i][k]*b.a[k][j];
}
c.a[i][j]%=(mod-1);
}
}
return c;
}
};
matrix mpow(matrix a,__int64 b)
{
matrix ans;
ans.clear();
ans.n=ans.m=a.n;
for(int i=0; i<a.n; i++)
{
ans.a[i][i]=1;
}
while(b)
{
if(b&1)
{
ans=ans*a;
}
a=a*a;
b>>=1;
}
return ans;
}
__int64 pow(__int64 a,__int64 b)
{
__int64 ans=1;
a=a%mod;
while(b)
{
if(b&1)
{
ans=ans*a%mod;
}
a=a*a%mod;
b>>=1;
}
return ans;
}
void print(matrix a)
{
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
cout<<a.a[i][j]<<" ";
}
cout<<endl;
}
cout<<"-----"<<endl;
}
matrix a;
__int64 ans;
__int64 t1,t2;
int main()
{
while(~scanf("%I64d%I64d%I64d",&x,&y,&t))
{
if(t==0)
{
printf("%I64d\n",x);
continue;
}
else if(t==1)
{
printf("%I64d\n",y);
continue;
}
else
{
a.clear();
a.n=a.m=2;
a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
a.a[1][1]=0;
a=mpow(a,t);
//print(a);
t1=a.a[1][1];
t2=a.a[0][1];
ans=0;
ans=(pow(x,t1)*pow(y,t2))%mod;
printf("%I64d\n",ans);
}
}
return 0;
}
HDU3936
/************************
http://acm.hdu.edu.cn/showproblem.php?pid=3936
题意:设定p[i]=f[i*4-1],给定一个区间,球在这个区间的p[i]的总和
思路:p[1] + p[2] + ... + p[n] = f[1]^2 + f[2]^2 + ... + f[2*n-1]^2 + f[2*n]^2 = f[2*n] * f[2*n+1]
这个题目比较蛋疼,谁会知道这么多的公式啊 ,不过知道这个公式后就简单了
Fibonacci数列通项公式∴F(n)=(1/√5)*{[(1+√5)/2]^(n+1) - [(1-√5)/2]^(n+1)}
性质:
1.f(0)+f(1)+f(2)+…+f(n)=f(n+2)-1。
2.f(1)+f(3)+f(5)+…+f(2n-1)=f(2n)。
3.f(2)+f(4)+f(6)+…+f(2n) =f(2n+1)-1。
4.[f(0)]^2+[f(1)]^2+…+[f(n)]^2=f(n)·f(n+1)。
5.f(0)-f(1)+f(2)-…+(-1)^n·f(n)=(-1)^n·[f(n+1)-f(n)]+1。
6.f(m+n-1)=f(m-1)·f(n-1)+f(m)·f(n)。
利用这一点,可以用程序编出时间复杂度仅为O(log n)的程序。
7.[f(n)]^2=(-1)^(n-1)+f(n-1)·f(n+1)。
8.f(2n-1)=[f(n)]^2-[f(n-2)]^2。
9.3f(n)=f(n+2)+f(n-2)。
10.f(2n-2m-2)[f(2n)+f(2n+2)]=f(2m+2)+f(4n-2m) [ n〉m≥-1,且n≥1]
11.f(2n+1)=[f(n)]^2+[f(n+1)]^2.
斐波那契数列的整除性与素数生成性
每3个数有且只有一个被2整除,
每4个数有且只有一个被3整除,
每5个数有且只有一个被5整除,
每6个数有且只有一个被8整除,
每7个数有且只有一个被13整除,
每8个数有且只有一个被21整除,
每9个数有且只有一个被34整除
************************/
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod 1000000007
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
struct matrix
{
int n,m;
__int64 a[5][5];
void clear()
{
memset(a,0,sizeof(a));
}
matrix operator +(const matrix &b)const
{
matrix c;
c.clear();
c.n=n,c.m=m;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
c.a[i][j]=(a[i][j]+b.a[i][j])%mod;
}
}
return c;
}
matrix operator *(const matrix &b)const
{
matrix c;
c.clear();
c.n=n,c.m=b.m;
for(int i=0; i<n; i++)
{
for(int j=0; j<b.m; j++)
{
for(int k=0; k<m; k++)
{
c.a[i][j]+=a[i][k]*b.a[k][j];
}
c.a[i][j]%=mod;
}
}
return c;
}
};
matrix pow(matrix a,__int64 b)
{
matrix ans;
ans.clear();
ans.n=ans.m=a.n;
for(int i=0; i<a.n; i++)
{
ans.a[i][i]=1;
}
while(b)
{
if(b&1)
{
ans=ans*a;
}
a=a*a;
b>>=1;
}
return ans;
}
int t;
__int64 l,r;
matrix a;
__int64 ans1,ans2;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%I64d%I64d",&l,&r);
a.clear();
a.n=a.m=2;
a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
a.a[1][1]=0;
ans1=(pow(a,2*r).a[0][1]*pow(a,2*r+1).a[0][1])%mod;
ans2=(pow(a,2*l-2).a[0][1]*pow(a,2*l-1).a[0][1])%mod;
printf("%I64d\n",(ans1-ans2+mod)%mod);
}
return 0;
}
HDU1568
这不是矩阵的题目,但是是斐波拉契的题目,在这儿列出主要原因是因为它和HDU3177有相似点,都是取菲波拉契数的前几位或者后几位,对候几位数,直接可以取模运算,对于前几位就回归到斐波拉切的本质上来 ,通过位数公式就可以求得
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define mod 10000
using namespace std;
__int64 fib[50];
__int64 solve(__int64 n)
{
double ans = -0.5 * log10(5.0) + n * log10((sqrt(5.0) + 1) / 2);
__int64 d = (__int64)ans;
ans -= d;
ans = pow(10.0, ans);
while(ans < 1000)
ans *= 10;
return (__int64)ans;
}
int main()
{
freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
int n;
fib[0]=0;
fib[1]=1;
for(int i=2; i<40; i++)
{
fib[i]=fib[i-1]+fib[i-2];
}
while(~scanf("%I64d",&n))
{
if(n<=20)
{
cout<<fib[n]<<endl;
continue;
}
printf("%I64d\n",solve(n));
}
return 0;
}
HDU3177
/************************
G++交
************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define mod 10000
using namespace std;
__int64 fib[50];
struct matrix
{
__int64 a[2][2];
void clear()
{
memset(a,0,sizeof(a));
}
matrix operator +(const matrix &b)const
{
matrix c;
c.clear();
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
c.a[i][j]=(a[i][j]+b.a[i][j])%mod;
}
}
return c;
}
matrix operator *(const matrix &b)const
{
matrix c;
c.clear();
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
for(int k=0; k<2; k++)
{
c.a[i][j]+=a[i][k]*b.a[k][j];
}
c.a[i][j]%=mod;
}
}
return c;
}
};
matrix power(matrix a,int b)
{
matrix ans;
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
ans.a[i][j]=(i==j);
}
}
while(b)
{
if(b&1)
ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
__int64 solve(__int64 n)
{
double ans = -0.5 * log10(5.0) + n * log10((sqrt(5.0) + 1) / 2);
__int64 d = (__int64)ans;
ans -= d;
ans = pow(10.0, ans);
while(ans < 1000)
ans *= 10;
return (__int64)ans;
}
int main()
{
// freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
int n;
fib[0]=0;
fib[1]=1;
for(int i=2; i<40; i++)
{
fib[i]=fib[i-1]+fib[i-2];
}
while(~scanf("%I64d",&n))
{
if(n<40)
{
cout<<fib[n]<<endl;
continue;
}
else
{
printf("%I64d...",solve(n));
matrix a,b;
a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
a.a[1][1]=0;
b=power(a,n);
printf("%04d\n",b.a[0][1]%mod);
}
}
return 0;
}
这是关于求位数的公式,在具体实现上面可以参考这个博客它里面讲解的比较好:http://hi.baidu.com/aekdycoin/item/a4407c37850e5b9db80c03a6
HDU1588
这个题目比较有意思,对于g(i)=k*i+b,,那么在【0,n-1】之内求f(g(i)),有前面这些题目的铺垫可知:f(i)=A^i,那么就有sum=f(g(0))+……f(g(n-1))
展开就有sum=f(b)+f(k+b)+……f((n-1)*k+b)
=A^b+A^(k+b)……A^((n-1)*k+b)
=A^b(A^0+A^k+A^2k+……A^((n-1)*k)) 在这儿就是把A^b提取公因数,记做AA
=A^b((A^0+(A^k)+(A^k)^2+……(A^k)^n-1) 把A^k作为一个公因式再提出来,记做K
=AA*(A^0+K^1+K^2+……K^(n-1))
这样就比较容易做出来了 只是要注意还有一个A^0要加上去
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<climits>
using namespace std;
__int64 mod;
struct matrix
{
__int64 a[2][2];
void init()
{
a[0][0]=a[1][1]=1;
a[0][1]=a[1][0]=0;
}
void clear()
{
memset(a,0,sizeof(a));
}
matrix operator +(const matrix &b)const
{
matrix c;
c.clear();
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
c.a[i][j]=(a[i][j]+b.a[i][j])%mod;
}
}
return c;
}
matrix operator *(const matrix &b)const
{
matrix c;
c.clear();
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
for(int k=0; k<2; k++)
{
c.a[i][j]+=(a[i][k]*b.a[k][j]);
}
c.a[i][j]=c.a[i][j]%mod;
}
}
return c;
}
};
matrix pow(matrix a,int b)
{
matrix ans;
ans.init();
while(b)
{
if(b&1)
{
ans=ans*a;
}
a=a*a;
b>>=1;
}
return ans;
}
matrix pow_sum(matrix a,int k)
{
matrix ans,temp;
if(k==1)return a;
temp=pow_sum(a,k>>1);
ans=temp+temp*pow(a,k>>1);
if(k&1)
{
ans=ans+pow(a,k);
}
return ans;
}
__int64 k,b,n;
int main()
{
//freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
// freopen("C:\\Users\\Administrator\\Desktop\\out.txt" , "w" , stdout);
matrix a,e,ab,ak,sum,ans;
while(~scanf("%I64d%I64d%I64d%I64d",&k,&b,&n,&mod))
{
a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
a.a[1][1]=0;
e.init();
ab=pow(a,b);
ak=pow(a,k);
sum=pow_sum(ak,n-1)+e;
ans=ab*sum;
printf("%d\n",ans.a[0][1]%mod);
}
return 0;
}