poj3233 矩阵等比数列求和 二分

对于数列S(n) = a + a^2 + a^3 +....+ a^n;

可以用二分的思想进行下列的优化。

if(n & 1)

  S(n) = a + a^2 + a^3 + ....... + a^n;

  = a + a^2 + a^3 +..+ a^((n-1) / 2) + a^((n-1) / 2 + 1) + a^((n-1) / 2 + 2) + ... + a^((n-1) / 2 + (n-1) / 2) + a^((n-1) / 2 + (n-1) / 2 + 1);

  = (1 + a^((n-1) / 2 + 1)) * S((n-1)/2) + a^((n-1) / 2 + 1)

else 

  S(n) = a + a^2 + a^3 + ....... + a^n;

  = a + a^2 + a^3 +..+ a^((n / 2) + a^(n / 2 + 1) + a^(n / 2 + 2) + ... + a^(n/ 2 + n / 2);

  = (1 + a^(n / 2)) * S(n / 2);

 

这样就可以避免矩阵的除法了! 还有就是MOD真的很慢。

#include<map>
#include<set>
#include<string>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<time.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 1000000001
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MAXN = 100010;
struct Mat
{
    ll a[45][45];
}E;
int n,k,MOD;
Mat Matadd(Mat a,Mat b)
{
    Mat c;
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            c.a[i][j] = (a.a[i][j] + b.a[i][j])%MOD;
        }
    }
    return c;
}
Mat Matmul(Mat a,Mat b)
{
    Mat c;
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            c.a[i][j] = 0;
            for(int k = 0; k < n; k++){
                c.a[i][j] += (a.a[i][k] * b.a[k][j])%MOD; 
            }
            c.a[i][j] %= MOD;
        }
    }
    return c;
}
Mat power(Mat a,int n)
{
    Mat c;
    c = E;
    while(n){
        if(n & 1){
            c = Matmul(c,a);
        }
        a = Matmul(a,a);
        n >>= 1;
    }
    return c;
}
Mat sum(Mat a,int k)//求S(k)
{
    if(k == 1)return a;
    Mat t = sum(a,k/2);//S(k/2)
    if(k & 1){
        Mat cur = power(a,k/2 + 1);//a^(k/2 + 1)
        t = Matadd(t,Matmul(t,cur));//(1 + a^(k/2+1))*S(k/2)
        t = Matadd(t,cur);//(1 + a^(k/2 + 1))*S(k/2)
    }
    else {
        Mat cur = power(a,k/2);//a^(k/2)
        t = Matadd(t,Matmul(t,cur));//(1 + a^(k/2))*S(k/2)
    }
    return t;
}
int main()
{
    while(scanf("%d%d%d",&n,&k,&MOD) != EOF){
        Mat a;
        memset(E.a,0,sizeof(E.a));
        for(int i = 0; i < n; i++)E.a[i][i] = 1;
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                scanf("%lld",&a.a[i][j]);
                a.a[i][j] %= MOD;
            }
        }
        Mat ans = sum(a,k);
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++){
                if(j == 0)printf("%lld",ans.a[i][j]);
                else {
                    printf(" %lld",ans.a[i][j]);
                }
            }
            printf("\n");
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/sweat123/p/5439432.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值