poj 3070;
这是弱的第一道矩阵快速幂,然后试试手,总之还是裸模板。但还是蛮难的
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int mod=10000;
ll n;
struct Matrix
{
ll ma[2][2];
Matrix()
{
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
ma[i][j]=0;
}
};
Matrix mult(Matrix a, Matrix b)
{
Matrix c;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
c.ma[i][j]=(c.ma[i][j]+a.ma[i][k]*b.ma[k][j]%mod)%mod;
}
}
}
return c;
}
Matrix pow(Matrix a,ll b)
{
Matrix temp;
for(int i=0;i<2;i++) temp.ma[i][i]=1;
while(b)
{
if(b&1) temp=mult(temp,a);
a=mult(a,a);
b>>=1;
}
return temp;
}
int main()
{
while(scanf("%I64d",&n)!=EOF)
{
if(n==-1) break;
else if(n==0) {printf("0\n"); continue;}
Matrix a,b;
a.ma[0][0]=1;
a.ma[0][1]=1;
a.ma[1][0]=1;
b=pow(a,n);
printf("%I64d\n",b.ma[0][1]%mod);
}
return 0;
}
poj 3725.
将每只猫的花生数放在一个1*n的矩阵中,考虑用k次操作构造成一个n*n矩阵A,因为三种操作中存在某种猫的花生数加一的操作,所以要把矩阵扩展一位放1,即[1,cnt1,cnt2,…,cntn],初始化矩阵A为单位矩阵,对于操作1,要把A[0][x]++;对于操作2,要令A[i][x]=0;对于操作3,要swap(A[i][x],A[i][y]),构造出A矩阵之后用矩阵快速幂求出A^m后第一行元素即为操作后每只猫的花生数. 但是弱还是不太会。看了题解,感觉这类题还是蛮神奇的。
#include <iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
ll n,m,k;
struct Matrix
{
ll ma[120][120];
Matrix()
{
for(int i=0;i<120;i++)
{
for(int j=0;j<120;j++)
{
ma[i][j]=0;
}
}
}
} ;
Matrix mult(Matrix a, Matrix b)
{
Matrix c;
for(int i=0;i<=n;i++)// 行
{
for(int j=0;j<=n;j++)
{
if(b.ma[i][j])
{
for(int k=0;k<=n;k++)
{
c.ma[i][k]=(c.ma[i][k]+a.ma[i][j]*b.ma[j][k]);
}
}
}
}
return c;
}
Matrix pow(Matrix a,ll b)
{
if(b==1) return a;
Matrix ans;
for(int i=0;i<=n;i++) ans.ma[i][i]=1;
while(b)
{
if(b & 1) ans=mult(ans,a);
b>>=1;
a=mult(a,a);
}
return ans;
}
int main()
{
while(scanf("%I64d%I64d%I64d",&n,&m,&k)!=EOF)
{
if(n==0&&m==0&&k==0) break;
Matrix x,y;
for(int i=0;i<=n;i++) x.ma[i][i]=1;
while(k--)
{
char s[5];
scanf("%s",s);
if(s[0]=='g')
{
int t;
scanf("%d",&t);
x.ma[0][t]++;
}
else if(s[0]=='e')
{
int t;
scanf("%d",&t);
for(int i=0;i<=n;i++)
x.ma[i][t]=0;
}
else
{
int p,q;
scanf("%d%d",&p,&q);
for(int i=0;i<=n;i++)
{
swap(x.ma[i][p],x.ma[i][q]);
}
}
}
y=pow(x,m);
for(int i=1;i<n+1;i++)
{
printf("%I64d",y.ma[0][i]);
if(i==n) printf("\n");
else printf(" ");
}
}
return 0;
}
poj 3233.很牛逼的一道题,就看了一眼题解。神马二分。。。弱完全没想到最后的方法。
a^1+a^2+a^3+a^4+a^5=(a^1+a^2+a^3+a^4)+a^5
(a^1+a^2+a^3+a^4)=(a^1+a^2+a^2(a^1+a^2))=(a^1+a^2)*(1+a^2)
(a^1+a^2)=a^1(1+a^1)
(a^1+a^2+a^3+a^4)=(a^1+a^2+a^2(a^1+a^2))=(a^1+a^2)*(1+a^2)
(a^1+a^2)=a^1(1+a^1)
如果k为偶数,那么(A+A^2+....A^K) = (A+...+A^K/2)+A^K/2*(A+...+A^K/2)
如果k为奇数,那么(A+A^2+....A^K) = (A+...+A^K/2)+A^K/2*(A+...+A^K/2)+A^k
讨论奇偶性
式子不会放大。。。
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
ll n,k,m;
struct Matix
{
ll ma[31][31];
Matix()
{
for(int i=0;i<31;i++)
{
for(int j=0;j<31;j++)
{
ma[i][j]=0;
}
}
}
};
Matix p,q,ans;
Matix mult(Matix a,Matix b)
{
Matix c;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
c.ma[i][j]=(c.ma[i][j]+a.ma[i][k]*b.ma[k][j])%m;
}
}
}
return c;
}
Matix sum(Matix a,Matix b)
{
Matix c;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
c.ma[i][j]=(a.ma[i][j]+b.ma[i][j])%m;
}
}
return c;
}
Matix pow(Matix a,ll b)
{
Matix ans;
for(int i=0;i<n;i++) ans.ma[i][i]=1;
while(b)
{
if(b&1) ans=mult(ans,a);
a=mult(a,a);
b>>=1;
}
return ans;
}
Matix solve(Matix m,ll k)
{
if(k==1) return m;
else if(k%2) return m=sum(solve(m,k-1),pow(m,k));
else return mult(solve(m,k/2),sum(p,pow(m,k/2)));
}
int main()
{
scanf("%I64d%I64d%I64d",&n,&k,&m);
for(int i=0;i<n;i++) p.ma[i][i]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%I64d",&q.ma[i][j]);
}
}
ans=solve(q,k);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
printf("%I64d",ans.ma[i][j]);
if(j==n-1) printf("\n");
else printf(" ");
}
}
return 0;
}