BM求递推式模板

#include <bits/stdc++.h>

using namespace std;
#define rep(i,a,n) for (long long i=a;i<n;i++)
#define per(i,a,n) for (long long i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((long long)(x).size())
typedef vector<long long> VI;
typedef long long ll;
typedef pair<long long,long long> PII;
const ll mod=1e9+7;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
// head

long long _,n;
namespace linear_seq
{
    const long long N=10010;
    ll res[N],base[N],_c[N],_md[N];

    vector<long long> Md;
    void mul(ll *a,ll *b,long long k)
    {
        rep(i,0,k+k) _c[i]=0;
        rep(i,0,k) if (a[i]) rep(j,0,k)
            _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
        for (long long i=k+k-1;i>=k;i--) if (_c[i])
            rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
        rep(i,0,k) a[i]=_c[i];
    }
    long long solve(ll n,VI a,VI b)
    { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
//        printf("%d\n",SZ(b));
        ll ans=0,pnt=0;
        long long k=SZ(a);
        assert(SZ(a)==SZ(b));
        rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
        Md.clear();
        rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
        rep(i,0,k) res[i]=base[i]=0;
        res[0]=1;
        while ((1ll<<pnt)<=n) pnt++;
        for (long long p=pnt;p>=0;p--)
        {
            mul(res,res,k);
            if ((n>>p)&1)
            {
                for (long long i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
                rep(j,0,SZ(Md)) 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);
        long long L=0,m=1,b=1;
        rep(n,0,SZ(s))
        {
            ll d=0;
            rep(i,0,L+1) 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.pb(0);
                rep(i,0,SZ(B)) 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.pb(0);
                rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
                ++m;
            }
        }
        return C;
    }
    long long gao(VI a,ll n)
    {
        VI c=BM(a);
        c.erase(c.begin());
        rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
        return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
    }
};

int main()
{
    while(~scanf("%I64d", &n))
    {   printf("%I64d\n",linear_seq::gao(VI{1,5,11,36,95,281,781,2245,6336,18061, 51205},n-1));
    }
}

原文地址:https://www.cnblogs.com/KatouKatou/p/9696173.html

时间: 2024-11-13 09:29:16

BM求递推式模板的相关文章

hiho 1143 矩阵快速幂 求递推式

题目链接: hihocoder 1143 思路见题目上 快速幂模板: // m^n % k int quickpow(int m,int n,int k) { int b = 1; while (n > 0) { if (n & 1) b = (b*m)%k; n = n >> 1 ; m = (m*m)%k; } return b; } 题解: #include<iostream> #include<cstdio> #include<cstring

2018ICPC焦作- Poor God Water 求递推式+矩阵快速幂

题目链接:https://nanti.jisuanke.com/t/31721 题意:一个孩子吃饭,有meat, fish 和 chocolate 三种食物可以选.要求连续三顿饭食物不能完全相同,鱼和肉的前一顿和后一顿不能都是巧克力,巧克力的左右两边不能同时出现鱼和肉. 思路:分九种情况,求出递推式,写出标准矩阵,用矩阵快速幂. 代码: #include <iostream> #include <stdio.h> #include <string.h> #define

【HDU4990】递推式

题目大意:给定序列 1, 2, 5, 10, 21, 42, 85, 170, 341 …… 求第n项 模 m的结果 递推式 f[i]  = f[i - 2] + 2 ^ (i - 1); 方法一: 构造矩阵, 求递推式 方法二: 直接推公式,递推式求和,得到 f[n] = [2 ^ (n + 1) - 1] / 3 奇数, f[n] = [2 ^ (n + 1) - 2] / 3 偶数: 其实还可以进一步化简, 注意到 2 ^ 2k % 3 = 1, 2 ^ (2k + 1) % 3 = 2,

HDU - 6172:Array Challenge (BM线性递推)

题意:给出,三个函数,h,b,a,然后T次询问,每次给出n,求sqrt(an); 思路:不会推,但是感觉a应该是线性的,这个时候我们就可以用BM线性递推,自己求出前几项,然后放到模板里,就可以求了. 数据范围在1e15,1000组都可以秒过. 那么主要的问题就是得确保是线性的,而且得求出前几项. #include<bits/stdc++.h> using namespace std; #define rep(i,a,n) for (int i=a;i<n;i++) #define per

51nod1149 Pi的递推式

基准时间限制:1 秒 空间限制:131072 KB 分值: 640 F(x) = 1 (0 <= x < 4) F(x) = F(x - 1) + F(x - pi) (4 <= x) Pi = 3.1415926535..... 现在给出一个N,求F(N).由于结果巨大,只输出Mod 10^9 + 7的结果即可. Input 输入一个整数N(1 <= N <= 10^6) Output 输出F(N) Mod 10^9 + 7 Input示例 5 Output示例 3 数学问

错排递推式推导

今天听课讲容斥,提到错排,突然发现错排公式什么的好像已经忘了233 努力地回忆了一下,算出前几项,终于还原出了那个递推式↓ f(n)=(n-1)*(f(n-1)+f(n-2)) 根据人赢的教导,只要思(yi)考(yin)下错排的构造就能记住了 然后就认(meng)认(you)真(yi)真(yang)地思(yi)考(yin)了下 用自己的理解把这玩意儿整理了一下↓ 先加一点平时我们说的错排通常是指1~n,f(i)≠i, 其实脑补一下,它也可以看成A,B两个集合,|A|=|B|,对于每一个Ai,都对

hdu 1757 A Simple Math Problem (构造矩阵解决递推式问题)

题意:有一个递推式f(x) 当 x < 10    f(x) = x.当 x >= 10  f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + -- + a9 * f(x-10) 同时ai(0<=i<=9) 不是 0 就是 1: 现在给你 ai 的数字,以及k和mod,请你算出 f(x)%mod 的结果是多少 思路:线性递推关系是组合计数中常用的一种递推关系,如果直接利用递推式,需要很长的时间才能计算得出,时间无法承受,但是现在我们已知

矩阵乘法来加速递推式计算

Codevs1281: 给你6个数,m, a, c, x0, n, g Xn+1 = ( aXn + c ) mod m,求Xn 计算递推式,运用矩阵来进行计算加速 然后注意用类似快速幂的方法写一个快速加,避免溢出 怎么把式子化成矩阵,日后再补 1 #include<cstdio> 2 long long mod,a,c,x0,n,g; 3 struct Mat 4 { 5 long long m[2][2]; 6 }base,X0; 7 long long quick_add(long lo

算法分析中递推式的一般代数解法 张洋

http://blog.codinglabs.org/articles/linear-algebra-for-recursion.html 另介绍一种算法 Berlekamp-Massey算法,常简称为BM算法,是用来求解一个数列的最短线性递推式的算法. #include <bits/stdc++.h> using namespace std; typedef long long ll; const double eps = 1e-7; const int maxn = 1e5 + 5; ve