HDU 1757
http://acm.hdu.edu.cn/showproblem.php?pid=1757
题意很清楚不同的X对应不同的FX,而且当X>=10时,有一个递推公式,因为N比较大,所以简单的暴力去写肯定不可能,所以要构造矩阵用快速幂解决。。。
思路:前10个FX简单保存下值,然后当X>=10时构造10*10的进行快速幂的矩阵 和10*1的初始矩阵。
大致可以写成/*****************************************
|0 1 0 0 0 0 0 0 0 0 | |f(x-10)| |f(x-9)|
|0 0 1 0 0 0 0 0 0 0 | |f(x-9) | |f(x-8)|
|0 0 0 1 0 0 0 0 0 0 | |f(x-8) | |f(x-7)|
|0 0 0 0 1 0 0 0 0 0 | |f(x-7) | |f(x-6)|
|0 0 0 0 0 1 0 0 0 0 |* |f(x-6) |= |f(x-5)|
|0 0 0 0 0 0 1 0 0 0 | |f(x-5) | |f(x-4)|
|0 0 0 0 0 0 0 1 0 0 | |f(x-4) | |f(x-3)|
|0 0 0 0 0 0 0 0 1 0 | |f(x-3) | |f(x-2)|
|0 0 0 0 0 0 0 0 0 1 | |f(x-2) | |f(x-1)|
|a9 a8 a7 a6 a5... a1| |f(x-1) | |f(x) |
******************************************/然后就O了,当时代码写的较矬 我自己都看不懂了。。。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int a[10][10];
int ans[10];
int k,m;
int f[20];
int b[10];
void fun()
{
memset(f,0,sizeof(f));
for(int i=0;i<=9;i++)
{
f[i]=i;
f[i]%=m;
}
for(int i=10;i<20;i++)
{
for(int j=0;j<=9;j++)
{
f[i]+=(b[j]*f[i-j-1])%m;
f[i]%=m;
}
}
}
void cheng1()
{
int temp[10];
memset(temp,0,sizeof(temp));
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
temp[i]+=(ans[j]*a[j][i])%m;
temp[i]%=m;
}
}
for(int i=0;i<10;i++)
{
ans[i]=temp[i];
}
}
void cheng2()
{
int temp1[10][10];
memset(temp1,0,sizeof(temp1));
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
for(int k=0;k<10;k++)
{
temp1[i][j]+=(a[i][k]*a[k][j])%m;
temp1[i][j]%=m;
}
}
}
for(int i=0;i<10;i++)
{
for(int j=0;j<10;j++)
{
a[i][j]=temp1[i][j];
}
}
}
int main()
{
while(cin>>k>>m)
{
memset(a,0,sizeof(a));
for(int i=0;i<10;i++)
{
cin>>b[i];
a[i][0]=b[i];
}
for(int i=1;i<10;i++)
{
a[i-1][i]=1;
}
fun();
if(k<=19)
{
cout<<f[k]<<endl;
}
else
{ k=k-19;
for(int i=0;i<10;i++)
{
ans[i]=f[19-i];
}
while(k)
{
if(k%2==0)
{
cheng2();
k/=2;
}
else
{
cheng1();
k--;
}
}
cout<<ans[0]<<endl;
}
}
return 0;
}
POJ 3233
求 S = A + A2 + A3 + … + Ak.
思路:对矩阵进行二分求和,若K为奇数,多出来的那个数直接快速幂,剩余的进行二分求和,然后二分进行递归按照是奇数单独拿一个去快速幂的思路可以敲出。
http://poj.org/problem?id=3233
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
struct juzhen{
int m[30][30];
};
int n,k,mod;
juzhen mut(juzhen a,juzhen b)
{
juzhen c;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
c.m[i][j]=0;
for(int k=0;k<n;k++)
{
c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
c.m[i][j]%=mod;
}
}
}
return c;
}
juzhen add(juzhen a,juzhen b)
{
juzhen c;
memset(c.m,0,sizeof(c.m));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
c.m[i][j]+=(a.m[i][j]+b.m[i][j])%mod;
c.m[i][j]%=mod;
}
}
return c;
}
juzhen pow(juzhen a,int p)
{
juzhen c;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i==j)
{
c.m[i][j]=1;
}
else
{
c.m[i][j]=0;
}
}
}
while(p)
{
if(p%2==0)
{
a=mut(a,a);
p/=2;
}
else
{
c=mut(c,a);
p--;
}
}
return c;
}
juzhen erfen(juzhen a,int p)
{
if(p==1)
return a;
if(p==2)
return add(a,mut(a,a));
if(p%2==1)
{
return add(erfen(a,p-1),pow(a,p));
}
if(p%2==0)
{
juzhen c;
c=erfen(a,p/2);//这里先进行二分省的进入递归时每次再进行这步操作可以提高效率。。一开始没优化狂T。
return add(c,mut(pow(a,p/2),c));
}
}
int main()
{
scanf("%d%d%d",&n,&k,&mod);
juzhen a;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%d",&a.m[i][j]);
}
}
a=erfen(a,k);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%d ",a.m[i][j]);
}
printf("\n");
}
return 0;
}
HDU 1588
http://acm.hdu.edu.cn/showproblem.php?pid=1588
也是矩阵二分求和,而且F是斐波那契矩阵只不过注意F(G(n))=F(K*n+b)=a^b(a^0+a^k+a^2k+a^3k+...a^(n-1)*k)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
struct juzhen{
long long m[2][2];
};
long long k,b,n,M;
juzhen mut(juzhen a,juzhen b)
{
juzhen c;
for(long long i=0;i<2;i++)
{
for(long long j=0;j<2;j++)
{
c.m[i][j]=0;
for(long long k=0;k<2;k++)
{
c.m[i][j]+=(a.m[i][k]*b.m[k][j])%M;
c.m[i][j]%=M;
}
}
}
return c;
}
juzhen add(juzhen a,juzhen b)
{
juzhen c;
memset(c.m,0,sizeof(c.m));
for(long long i=0;i<2;i++)
{
for(long long j=0;j<2;j++)
{
c.m[i][j]+=(a.m[i][j]+b.m[i][j])%M;
c.m[i][j]%=M;
}
}
return c;
}
juzhen pow(juzhen a,long long p)
{
juzhen b;
b.m[0][0]=b.m[1][1]=1;
b.m[0][1]=b.m[1][0]=0;
while(p)
{
if(p%2==0)
{
a=mut(a,a);
p/=2;
}
else
{
b=mut(b,a);
p--;
}
}
return b;
}
juzhen erfen(juzhen a,long long p)
{
if(p==1)
return a;
if(p==2)
return add(a,mut(a,a));
if(p%2==1)
{
return add(erfen(a,p-1),pow(a,p));
}
if(p%2==0)
{
juzhen c;
c=erfen(a,p/2);
return add(c,mut(pow(a,p/2),c));
}
}
int main()
{
while(cin>>k>>b>>n>>M)
{
juzhen a;
a.m[0][0]=a.m[0][1]=a.m[1][0]=1;
a.m[1][1]=0;
juzhen aa;
aa=pow(a,b);
juzhen bb;
bb=pow(a,k);
juzhen cc;
cc=erfen(bb,n-1);
juzhen dd;
dd=mut(aa,cc);
juzhen ans;
ans=add(aa,dd);
cout<<ans.m[0][1]<<endl;
}
return 0;
}
HDU 3306
http://acm.hdu.edu.cn/showproblem.php?pid=3306
Now we define another kind of Fibonacci : A(0) = 1 , A(1) = 1 , A(N) = X * A(N - 1) + Y * A(N - 2) (N >= 2).And we want to Calculate S(N) , S(N) = A(0)2 +A(1)2+……+A(n)2.
首先把AN平方有A(N)^2=X^2*A(N-1)^2+Y^2*A(N-2)^2+2*X*Y*A(N-1)*A(N-2) ,根据这个式子可以构造:
|1 x*x y*y 2*x*y| | SUMN | | SUMN+1 |
|0 x*x y*y 2*x*y| | 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) |
特别注意A(N)*A(N-1)=(X*A(N-1)+Y*A(N-2))*A(N-1)=X*A(N-1)^2+Y*A(N-1)*(N-2)故最后一阶构造成0 X 0 Y的形式
剩下的。。就是注意取余的问题了。。
当然如果下次要求SUM类的矩阵记得在原定义的矩阵上多加一阶用来存放SUM的值然后就O了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,x,y;
const int mod=10007;
struct juzhen {
int m[4][4];
};
juzhen mut(juzhen a,juzhen b)
{
juzhen c;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
c.m[i][j]=0;
for(int k=0;k<4;k++)
{
c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
c.m[i][j]%=mod;
}
}
}
return c;
}
juzhen pow(juzhen a,int p)
{
juzhen b;
memset(b.m,0,sizeof(b.m));
for(int i=0;i<4;i++)
{
b.m[i][i]=1;
}
while(p)
{
if(p%2==0)
{
a=mut(a,a);
p/=2;
}
else
{
b=mut(b,a);
p--;
}
}
return b;
}
int main()
{
while(cin>>n>>x>>y)
{
juzhen a;
x%=mod;
y%=mod;
a.m[0][0]=a.m[2][1]=1;
a.m[1][0]=a.m[2][0]=a.m[3][0]=a.m[2][2]=a.m[2][3]=a.m[3][2]=0;
a.m[0][1]=a.m[1][1]=(x*x)%mod;
a.m[0][2]=a.m[1][2]=(y*y)%mod;
a.m[0][3]=a.m[1][3]=(2*x*y)%mod;
a.m[3][1]=x%mod;
a.m[3][3]=y%mod;
juzhen ans;
ans=pow(a,n-1);
int sum;
sum=(2*ans.m[0][0]+ans.m[0][1]+ans.m[0][2]+ans.m[0][3])%mod;
cout<<sum<<endl;
}
return 0;
}
今天先写简单写下四题。。大概刷了12题,然后明天有时间更新2和3,智商比较低代码比较挫还望勿见怪,实力有限。。还得继续努力。。。
.