杜教BM

杜教BM

1.算法分析

黑科技…输入线性递推的前几项,可以输出第n项

2.模板

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for (int i = a; i < n; i++)
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
const ll mod = 1e9 + 7;
ll powmod(ll a, ll b) {
    ll ret = 1;
    a %= mod;
    while (b) {
        if (b & 1) ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}
int _, n;
namespace linear_seq {
const int N = 10010;
ll res[N], base[N], _c[N], _md[N];
vector<int> Md;
void mul(ll *a, ll *b, int k) {
    for (int i = 0; i < k + k; i++) _c[i] = 0;
    for (int i = 0; i < k; ++i)
        if (a[i])
            for (int j = 0; j < k; j++)
                _c[i + j] = (_c[i + j] + a[i] * b[j]) % mod;
    for (int i = k + k - 1; i >= k; i--)
        if (_c[i])
            for (int j = 0; j < (int)Md.size(); j++)
                _c[i - k + Md[j]] =
                    (_c[i - k + Md[j]] - _c[i] * _md[Md[j]]) % mod;
    for (int i = 0; i < k; i++) a[i] = _c[i];
}
int solve(ll n, VI a, VI b) {
    ll ans = 0, pnt = 0;
    int k = SZ(a);
    for (int i = 0; i < k; i++) _md[k - 1 - i] = -a[i];
    _md[k] = 1;
    Md.clear();
    for (int i = 0; i < k; i++)
        if (_md[i] != 0) Md.push_back(i);
    for (int i = 0; i < k; i++) res[i] = base[i] = 0;
    res[0] = 1;
    while ((1ll << pnt) <= n) pnt++;
    for (int p = pnt; p >= 0; p--) {
        mul(res, res, k);
        if ((n >> p) & 1) {
            for (int i = k - 1; i >= 0; i--) res[i + 1] = res[i];
            res[0] = 0;
            for (int j = 0; j < (int)Md.size(); ++j)
                res[Md[j]] = (res[Md[j]] - res[k] * _md[Md[j]]) % mod;
        }
    }
    rep(i, 0, k) ans = (ans + res[i] * b[i]) % mod;
    if (ans < 0) ans += mod;
    return ans;
}
VI BM(VI s) {
    VI C(1, 1), B(1, 1);
    int L = 0, m = 1, b = 1;
    for (int n = 0; n < (int)s.size(); ++n) {
        ll d = 0;
        for (int i = 0; i < L + 1; i++) d = (d + (ll)C[i] * s[n - i]) % mod;
        if (d == 0)
            ++m;
        else if (2 * L <= n) {
            VI T = C;
            ll c = mod - d * powmod(b, mod - 2) % mod;
            while (SZ(C) < SZ(B) + m) C.push_back(0);
            for (int i = 0; i < (int)B.size(); i++)
                C[i + m] = (C[i + m] + c * B[i]) % mod;
            L = n + 1 - L;
            B = T;
            b = d;
            m = 1;
        } else {
            ll c = mod - d * powmod(b, mod - 2) % mod;
            while (SZ(C) < SZ(B) + m) C.push_back(0);
            for (int i = 0; i < (int)B.size(); i++)
                C[i + m] = (C[i + m] + c * B[i]) % mod;
            ++m;
        }
    }
    return C;
}
ll gao(VI a, ll n) {
    VI c = BM(a);
    c.erase(c.begin());
    for (int i = 0; i < (int)c.size(); i++) c[i] = (mod - c[i]) % mod;
    return (ll)solve(n, c, VI(a.begin(), a.begin() + SZ(c)));
}
}  // namespace linear_seq
int main() {
    ll nnn;
    VI a;  //下面几行是“找规律”的前几个数字
    a.push_back(2);
    a.push_back(24);
    a.push_back(96);
    a.push_back(416);
    a.push_back(1536);
    a.push_back(5504);
    a.push_back(18944);
    a.push_back(64000);
    a.push_back(212992);
    a.push_back(702464);
    scanf("%lld", &nnn);
    printf("%lld\n", linear_seq::gao(a, nnn - 1));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值