HDU4549 M斐波那契数列(矩阵快速幂+欧拉定理)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4549
中文题目读起来就是爽啊,常规做了一遍,妥妥超时了,看那个a,b的指数满足斐波那契数列,所以用矩阵来构造。然后在WA了很多遍找不到错误的情况下,后来看了下网上的题解,才知道在做矩阵乘法的时候即使用long long也有可能溢出~题目要求对10000000007取模,是个质数。A^B%C,且C为质数,A,C互质,利用数论的知识可以得到:
A^B%C=A^(B%(C-1))%C;
代码:
<span style="font-family:FangSong_GB2312;font-size:18px;">#include <stdio.h>
#include <string.h>
#define mod 1000000007
#define Max_dimension 2
typedef long long LL;
typedef LL Matrix[Max_dimension][Max_dimension];
int ndim=Max_dimension;
Matrix A={{1,1},{1,0}};
void m_zero(Matrix x)
{
memset(x,0,sizeof(LL)*Max_dimension*Max_dimension);
}
void m_one(Matrix x)
{
m_zero(x);
for(int i=0;i<ndim;i++)
x[i][i]=1;
}
void m_copy(Matrix src,Matrix dest)
{
memcpy(dest,src,sizeof(LL)*Max_dimension*Max_dimension);
}
void m_multiple(Matrix a,Matrix b,Matrix c)
{
for(int i=0;i<ndim;i++)
for(int j=0;j<ndim;j++)
{
c[i][j]=0;
for(int k=0;k<ndim;k++)
{
c[i][j]+=(a[i][k]*b[k][j])%(mod-1);
c[i][j]%(mod-1);
}
}
}
void m_pow(Matrix x,int m,Matrix y)
{
Matrix temp,temp_x;
m_one(y);
m_copy(x,temp_x);
while(m)
{
if(m&1)
{
m_multiple(temp_x,y,temp);
m_copy(temp,y);
}
if(m>>=1)
{
m_multiple(temp_x,temp_x,temp);
m_copy(temp,temp_x);
}
}
}
LL quick_pow(LL t,LL m)
{
LL tmp=t%mod;
LL ant=1;
while(m)
{
if(m&1)
{
ant*=tmp;
ant%=mod;
}
m>>=1;
tmp*=tmp;
tmp%=mod;
}
return ant;
}
//Matrix B={{1},{2}};
int main()
{
//freopen("in.txt","r",stdin);
int a,b,n;
Matrix ans;
while(scanf("%d%d%d",&a,&b,&n)!=EOF)
{
m_zero(ans);
if(n)
m_pow(A,n-1,ans);
else
{
ans[0][0]=0;
ans[1][0]=1;
}
//m_multiple(ans,B,res); //b的次幂
LL num1=quick_pow(b,ans[0][0])%mod;
LL num2=quick_pow(a,ans[1][0])%mod;
printf("%d\n",num1*num2%mod);
}
return 0;
}
/*
100 10 3
10 10 5
*/</span>
HDU2254 奥运
链接:http://acm.hdu.edu.cn/showproblem.php?pid=2254
如果能够想到用矩阵的话,这道题目就不难做,求两个城市之间的走法,在限制时间内达到,矩阵幂之和即可·····用STL的map来保存每个点·····
代码:
<span style="font-family:FangSong_GB2312;font-size:18px;">#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
using namespace std;
#define mod 2008
#define size 30
int ndim;
struct Matrix
{
int a[size][size];
}tem;
Matrix m_one(Matrix x)
{
for(int i=0;i<30;i++)
for(int j=0;j<30;j++)
if(i==j)
x.a[i][j]=1;
else
x.a[i][j]=0;
return x;
}
Matrix m_add(Matrix a,Matrix b)
{
Matrix c;
for(int i=0;i<ndim;i++)
for(int j=0;j<ndim;j++)
{
c.a[i][j]=(a.a[i][j]+(_int64)b.a[i][j])%mod;
c.a[i][j]%=mod;
}
return c;
}
Matrix m_multiple(Matrix a,Matrix b)
{
Matrix c;
for(int i=0;i<ndim;i++)
for(int j=0;j<ndim;j++)
{
c.a[i][j]=0;
for(int k=0;k<ndim;k++)
{
c.a[i][j]+=(a.a[i][k]*(_int64)b.a[k][j])%mod;
c.a[i][j]%=mod;
}
}
return c;
}
Matrix m_pow(Matrix x,int m)
{
Matrix temp;
temp=x;
x=m_one(x);
while(m)
{
if(m&1)
x=m_multiple(x,temp);
temp=m_multiple(temp,temp);
m>>=1;
}
return x;
}
Matrix m_pow_sum(Matrix x,int p)
{
//Matrix tem;
if(p==1)
return x;
else if(p&1)
return m_add(m_pow(x,p),m_pow_sum(x,p-1));
else
return m_multiple(m_pow_sum(x,p>>1),m_add(m_pow(x,p>>1),tem));
}
int main()
{
int T,n,k,t1,t2,v1,v2;
int x,y,num;
map<int,int> mapp;
Matrix res,s1,s2;
tem=m_one(tem);
while(scanf("%d",&T)!=EOF)
{
for(int i=0;i<30;i++)
for(int j=0;j<30;j++)
res.a[i][j]=0;
num=0;
mapp.clear();
while(T--)
{
scanf("%d%d",&x,&y);
if(!mapp.count(x))
mapp[x]=num++;
if(!mapp.count(y))
mapp[y]=num++;
res.a[mapp[x]][mapp[y]]++; //记录这两点之间有几种走法
}
ndim=num;
scanf("%d",&k);
while(k--)
{
scanf("%d%d%d%d",&v1,&v2,&t1,&t2);
if(t2<t1|| mapp.count(v1)==0 || mapp.count(v2)==0 )
{
printf("0\n");
continue;
}
int p1=0,p2=0;
Matrix r=res;
if(t1>1)
{
s1=m_pow_sum(r,t1-1);
p1=s1.a[mapp[v1]][mapp[v2]];
}
if(t2>=1)
{
s2=m_pow_sum(r,t2);
p2=s2.a[mapp[v1]][mapp[v2]];
}
printf("%d\n",(p2-p1+mod)%mod);
}
}
return 0;
}
</span>
HDU2604 Queuing
链接:http://acm.hdu.edu.cn/showproblem.php?pid=2604
题意:用m和f来随机排列,但是不可以出现fmf和fff的形式,问有多少种方式
分析:f(n)表示n个人的排列方法···这样考虑:
如果前边的人都符合题意,那么f(n)就是f(n-1)在增添一个人,但是不能出现那两种形式。想象f(n-1)是合法的,再增添一个m是合法的,有f(n-1)种····
但是如果最后一个人是m,则f(n-1)可以是f或者m结尾,则要看f(n-2),但是这ff和mf都不能直接确定是不是合法,再向前看一个,即f(n-3),就有4种形式了,mm,mf,fm,ff分别和f组合,fm,ff显然不合法,去掉。mmf无限制,f(n-3)种···
还剩一个mf,仅看f(n-3)是无法看出能不能放,再向前看一个,即f(n-4),mmff是无限制的,所以f(n-4)种
综上:f(n)=f(n-1)+f(n-3)+f(n-4)
置于矩阵呢,很好构造,
A={{1,0,1,1},{1,0,0,0},{0,1,0,0,},{0,0,1,0}}
代码:
<span style="font-family:FangSong_GB2312;font-size:18px;">#include <stdio.h> #include <string.h> #include <stdlib.h> #define Max_dimension 4 //#define mod 2008 typedef int Matrix_type; typedef long long Max_int_type; typedef Matrix_type Matrix[Max_dimension][Max_dimension]; int mod; int ndim=Max_dimension; void m_zero(Matrix x) { memset(x,0,sizeof(Matrix_type)*Max_dimension*Max_dimension); } void m_one(Matrix x) { m_zero(x); for(int i=0;i<ndim;i++) x[i][i]=1; } void m_copy(Matrix src,Matrix dest) { memcpy(dest,src,sizeof(Matrix_type)*Max_dimension*Max_dimension); } //c=a*b void m_multiple(Matrix a,Matrix b,Matrix c) { int i,j,k; for(i=0;i<ndim;i++) for(j=0;j<ndim;j++) { c[i][j]=0; if(mod<=1) for(k=0;k<ndim;k++) c[i][j]+=a[i][k]*b[k][j]; else for(k=0;k<ndim;k++) { c[i][j]+=(a[i][k]*(Max_int_type)b[k][j])%mod; c[i][j]%=mod; } } } //y=x^n void m_pow(Matrix x, unsigned int n, Matrix y) { Matrix temp,temp_x; m_one(y); m_copy(x,temp_x); while(n) { if (n&1) { m_multiple(temp_x,y,temp); m_copy(temp,y); } if (n >>= 1) { m_multiple(temp_x,temp_x,temp); m_copy(temp,temp_x); } } } Matrix A={{1,0,1,1},{1,0,0,0},{0,1,0,0,},{0,0,1,0}}; Matrix B={{9},{6},{4},{2}}; int main() { //freopen("in.txt","r",stdin); Matrix ans,sum; int l; while(scanf("%d%d",&l,&mod)!=EOF) { if(l==0) { printf("0\n"); continue; } if(l==1) { printf("%d\n",2%mod); continue; } if(l==2) { printf("%d\n",4%mod); continue; } if(l==3) { printf("%d\n",6%mod); continue; } if(l==4) { printf("%d\n",9%mod); continue; } m_pow(A,l-4,ans); m_multiple(ans,B,sum); printf("%d\n",sum[0][0]%mod); } return 0; }</span>