Arc of Dream

这篇博客介绍了如何解决一个数列求和问题,通过设立f[n]和Aob[n]的关系,推导出转移方程,并利用矩阵加速来优化复杂度。虽然在实现过程中遇到了超时问题,但通过特判n=0的情况,最终解决了问题。
摘要由CSDN通过智能技术生成

题目大意

转送门
让你求一个数列的第n个数

思路

我们设 f [ n ] = a [ n ] × b [ n ] f[n]=a[n]\times b[n] f[n]=a[n]×b[n],而 A o b [ n ] = ∑ i = 0 n − 1 a [ i ] × b [ i ] Aob[n]=\sum_{i=0}^{n-1}a[i]\times b[i] Aob[n]=i=0n1a[i]×b[i],所以 A o b [ n ] = A o b [ n − 1 ] + f [ n − 1 ] Aob[n]=Aob[n-1]+f[n-1] Aob[n]=Aob[n1]+f[n1],而 f [ n − 1 ] = a [ n ] × b [ n ] f[n-1]=a[n]\times b[n] f[n1]=a[n]×b[n], a [ n ] = a [ n − 1 ] × A X + A Y a[n]=a[n-1]\times AX + AY a[n]=a[n1]×AX+AY, b [ n ] = b [ n − 1 ] × B X + B Y b[n]=b[n-1]\times BX + BY b[n]=b[n1]×BX+BY,所以 f [ n − 1 ] = ( a [ n − 2 ] × A X + A Y ) × ( b [ n − 2 ] ∗ B X + B Y ) = A X × B X × a [ n − 2 ] × b [ n − 2 ] + b [ n − 2 ] × B X × A Y + a [ n − 2 ] × A X × B Y + A Y × B Y = A X ∗ B X ∗ f [ n − 2 ] + b [ n − 2 ] × B X × A Y + a [ n − 2 ] × A X × B Y + A Y × B Y f[n-1]=(a[n-2]\times AX+AY)\times (b[n-2]*BX+BY)=AX\times BX\times a[n-2]\times b[n-2]+b[n-2]\times BX\times AY+a[n-2]\times AX\times BY+AY\times BY=AX*BX*f[n-2]+b[n-2]\times BX\times AY + a[n-2]\times AX\times BY + AY\times BY f[n1]=(a[n2]×AX+AY)×(b[n2]BX+BY)=AX×BX×a[n2]×b[n2]+b[n2]×BX×AY+a[n2]×AX×BY+AY×BY=AXBXf[n2]+b[n2]×BX×AY+a[n2]×AX×BY+AY×BY,所以,我们 f [ n ] f[n] f[n]就可以通过 f [ n − 1 ] f[n-1] f[n1]转移过来,所以 A o b [ n ] Aob[n] Aob[n]也可以通过 A o b [ n − 1 ] Aob[n-1] Aob[n1]转移过来,我们也可以利用矩阵加速了。因为我比较菜,所以,我构造了一个7个数的初始矩阵, 7 × 7 7\times 7 7×7的转移矩阵,长成这个样子:

既然初始矩阵都有了,那我就不给出转移矩阵了吧因为我懒得画,代码里面也有。然后,我们就可以成功地 O ( 7 3 l o g n ) O(7^3logn) O(73logn)解决了,诶?怎么超时了?要特判 n = 0 n=0 n=0的情况,好吧,好像……,好像就没有什么了

代码

#pragma GCC optimize (2)
#include <set>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define Int register int
#define mod 1000000007
#define int long long
#define MAXN 10

struct Matrix
{
    int n,m;
    int a[MAXN][MAXN];
    Matrix(){memset (a,0,sizeof (a));}
    Matrix operator * (const Matrix &p)const
    {
        Matrix New;
        New.n = n,New.m = p.m;
        for (Int i = 1;i <= New.n;++ i)
            for (Int j = 1;j <= New.m;++ j)
                for (Int k = 1;k <= m;++ k)
                    New.a[i][j] = (New.a[i][j] + a[i][k] % mod * p.a[k][j] % mod) % mod;
        return New;
    }
};

Matrix quick_pow (Matrix a,int b)
{
    Matrix res;
    res.n = res.m = a.n;
    for (Int i = 1;i <= res.n;++ i) res.a[i][i] = 1;
    while (b)
    {
        if (b & 1)
            res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}

void read (int &x)
{
    x = 0;char c = getchar();int f = 1;
    while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}
    while (c >= '0' && c <= '9'){x = (x << 3) + (x << 1) + c - '0';c = getchar();}
    x *= f;return ;
}

void write (int x)
{
    if (x < 0){x = -x;putchar ('-');}
    if (x > 9) write (x / 10);
    putchar (x % 10 + '0');
}

signed main()
{
    int N;
    while (~scanf ("%lld",&N))
    {
        int A0,Ax,Ay,B0,Bx,By;
        read (A0),read (Ax),read (Ay),read (B0),read (Bx),read (By);
        A0 %= mod,Ax %= mod,Ay %= mod,B0 %= mod,Bx %= mod,By %= mod;
        if (N == 0)
        {
            write (0),putchar ('\n');
            continue;
        }
        if (N == 1)
        {
            write (A0 % mod * B0 % mod),putchar ('\n');
            continue;
        }
        Matrix A,B,C;
        A.n = 7,A.m = 1;
        int A1 = A0 % mod * Ax % mod + Ay % mod,B1 = B0 % mod * Bx % mod + By % mod;
        A1 %= mod,B1 %= mod;
        A.a[1][1] = A0 % mod * B0 % mod,A.a[2][1] = A1 % mod * B1 % mod,A.a[3][1] = A1 % mod,A.a[4][1] = B1 % mod,
        A.a[5][1] = Ay % mod * By % mod,A.a[6][1] = Ay % mod,A.a[7][1] = By % mod;
        B.n = 7,B.m = 7;
        B.a[1][1] = B.a[1][2] = B.a[2][5] = B.a[3][6] = B.a[4][7] = B.a[5][5] = B.a[6][6] = B.a[7][7] = 1;
        B.a[2][2] = Ax % mod * Bx % mod,B.a[2][3] = Ax % mod * By % mod,B.a[2][4] = Ay % mod * Bx % mod;
        B.a[3][3] = Ax % mod,B.a[4][4] = Bx % mod;
        C = quick_pow (B,N - 1) * A;
        write (C.a[1][1]),putchar ('\n');    
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值