等比数列是指从第二项起,每一项与它的前一项的比值等于同一个常数的一种数列。对于一个等比数列an=a1 * qn-1,它的前n项的和Sn=a1 * (1-qn)/(1-q)(q≠1)。现在已知A为n*n的矩阵,S=A+A2+A3+…+Am,你能否正确求出S,并且输出S中的每一个元素对1000000007取模后的值。
输入
输入包括n+1行,第一行包括两个正整数n, m,分别代表矩阵A的大小和S中的项数,其中1≤n≤30, 1≤m≤109。接下来n行,每行n个元素,相应地代表A中的元素x,其中0≤x≤106。
输出
输出包括n行,每行n个元素,相应地代表S中的每一个元素对1000000007取模后的值。
样例输入 Copy
1 2019
1
样例输出 Copy
2019
第一反应就是分治,因为等比可分治。
纪念lz学长,带老。
不过题解不是分治写的。
这里就都记一下啦,分治公式以后用到了自己推。。
分治写法:
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<queue>
#define ll long long
using namespace std;
const int maxn=35;
const int mod=1000000007;
struct node
{
ll a[maxn][maxn];
}res;
int n,m;
node operator * (const node &a,const node &b)
{
node c;
memset(c.a,0,sizeof(c.a));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
}
}
}
return c;
}
node operator +(const node &a,const node &b)
{
node c;
memset(c.a,0,sizeof(c.a));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
c.a[i][j]=(a.a[i][j]+b.a[i][j])%mod;
}
return c;
}
node mypow(node a,ll b)
{
node ans;
memset(ans.a,0,sizeof(ans.a));
for(int i=1;i<=n;i++)
ans.a[i][i]=1;
while(b)
{
if(b&1) ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
node getans(ll now)
{
if(now==1)
return res;
node c=getans(now/2);
if(now&1)
{
node d=mypow(res,now/2+1);
node e=c*d+d+c;
return e;
}
else return c*mypow(res,now/2)+c;
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%lld",&res.a[i][j]);
}
}
node ans=getans(m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(j!=1) putchar(' ');
printf("%lld",ans.a[i][j]);
}
putchar('\n');
}
return 0;
}
题解:
懒得写了,记录一下这种解法。