這是關於斐波拉切的經典操作
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;
}