Matrix Power Series
Time Limit: 3000MS |
|
Memory Limit: 131072K |
Total Submissions: 10211 |
|
Accepted: 4333 |
Description
Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak.
Input
The input contains exactly one test case. The first line of input contains three positive integers n (n ≤ 30), k (k ≤ 109) and m (m < 104). Then follow n lines each containing n nonnegative integers below 32,768, giving A’s elements in row-major order.
Output
Output the elements of S modulo m in the same way as A is given.
Sample Input
2 2 4
0 1
1 1
Sample Output
1 2
2 3
题意很简单不用描述了
网上在推荐这题的时候可能有些误区
网上说是二分再二分,
其实是这样的,因为计算a^k可以二分,这是第二个二分
而第一个二分是指的对a^1+a^2+....+a^k可以分成两半
k是偶数时候
f[k]=(a^1+a^2+....+a^(k/2))+a^(k/2)*[a^1+a^2+....+a^(k/2)]
即 f[k]=f[k/2]+[a^(k/2)]*f[k/2]
奇数时候
f[k]=f[k-1]+a^k
以上描述的两次二分是第一种做法
第二种做法
运用线性代数的
令B= A E
0 E
那么
B^(k+1)= A^(k+1) E+A+...A^k
0 E
然后就不用多说了
刚开始想出第一种方法,觉着也不难写 ,
然后wa到死 tle到死
一直超时,那个取模那个如果不取就wa,取了就tle,真心纠结了
然后忍不了了
写的第二个
不知道为什么还是那么长时间
应该是我写的代码质量不好
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#define maxn 35*2
using namespace std;
struct node
{
__int64 x[maxn][maxn];
void init()
{
memset(x,0,sizeof(x));
}
void init1()
{
memset(x,0,sizeof(x));
for(int i=1; i<maxn; i++)
x[i][i]=1;
}
};
node e;
int m,n,k;
void print1(node x)
{
for(int i=1; i<=n; i++)
{
for(int j=1+n; j<=2*n; j++)
{
printf("%d",x.x[i][j]);
if(j==n*2) printf("\n");
else printf(" ");
}
}
}
node add1(node x)
{
node tmp;
tmp=x;
for(int i=1;i<=n;i++)
{
for(int j=n+1;j<=2*n;j++)
tmp.x[i][j]=(tmp.x[i][j]%m+m)%m;
}
for(int i=1; i<=n; i++)
tmp.x[i][i+n]=(tmp.x[i][i+n]-1+m)%m;
return tmp;
}
node mul(node t1,node t2)
{
node tmp;
tmp.init();
for(int i=1; i<=2*n; i++)
for(int j=1; j<=2*n; j++)
{
tmp.x[i][j]=0;
for(int k=1; k<=2*n; k++)
{
tmp.x[i][j]=(tmp.x[i][j]+t1.x[i][k]*t2.x[k][j])%m;
}
}
return tmp;
}
node ap(node a,int p)
{
int tmp;
node x,ans;
tmp=p;
ans.init1();
x=a;
while(tmp)
{
if(tmp%2==1) ans=mul(ans,x);
tmp=tmp/2;
x=mul(x,x);
}
return ans;
}
int main()
{
node a,ans,b;
scanf("%d%d%d",&n,&k,&m);
a.init();
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
scanf("%d",&a.x[i][j]);
a.x[i][j]=a.x[i][j]%m;
}
b=a;
for(int j=1; j<=n; j++)
{
b.x[j][j+n]=1;
b.x[j+n][j+n]=1;
}
ans=ap(b,k+1);
ans=add1(ans);
print1(ans);
return 0;
}
那个第一种方法tle,待会去优化下代码,应该能过
呼,第一种方法终于过了
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
#define maxn 35
#define inf 0x7fffffff
using namespace std;
struct node
{
__int64 x[maxn][maxn];
void init()
{
memset(x,0,sizeof(x));
}
void init1()
{
memset(x,0,sizeof(x));
for(int i=1; i<maxn; i++)
x[i][i]=1;
}
};
node e;
int m,n,k;
void print(node x)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
printf("%d",x.x[i][j]);
if(j==n) printf("\n");
else printf(" ");
}
}
}
node add(node t1,node t2)
{
node tmp;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
tmp.x[i][j]=(t1.x[i][j]+t2.x[i][j])%m;
}
return tmp;
}
node mul(node t1,node t2)
{
node tmp;
tmp.init();
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
tmp.x[i][j]=0;
for(int k=1; k<=n; k++)
{
tmp.x[i][j]=(tmp.x[i][j]+t1.x[i][k]*t2.x[k][j]);
if(tmp.x[i][j]>=inf)
{
tmp.x[i][j]=tmp.x[i][j]%m;
}
}
tmp.x[i][j]=(tmp.x[i][j])%m;
}
return tmp;
}
node ap(node a,int p)
{
int tmp;
node x,ans;
tmp=p;
ans.init1();
x=a;
while(tmp)
{
if(tmp%2==1) ans=mul(x,ans);
tmp=tmp/2;
x=mul(x,x);
}
return ans;
}
node getsum(node x,int n)
{
int k;
node ans,tmp;
k=n;
if(k==1) return x;
if (k%2==0)
{
tmp=getsum(x,k/2);
ans=add(tmp,mul(ap(x,k/2),tmp));
}
else
{
tmp=getsum(x,k/2);
ans=add(add(tmp,mul(ap(x,k/2),tmp)),ap(x,k));
}
return ans;
}
int main()
{
node a,ans,b;
scanf("%d%d%d",&n,&k,&m);
a.init();
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
scanf("%d",&a.x[i][j]);
a.x[i][j]=a.x[i][j]%m;
}
ans=getsum(a,k);
print(ans);
return 0;
}