BM递推杜教版扩展
Posted lfri
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BM递推杜教版扩展相关的知识,希望对你有一定的参考价值。
也就是模数不是质数的时候,
//下面的板子能求质数和非质数,只需要传不同的参数。
#include <cstdio> #include <cstdlib> #include <cassert> #include <cstring> #include <bitset> #include <cmath> #include <cctype> #include <unordered_map> #include <iostream> #include <algorithm> #include <string> #include <vector> #include <queue> #include <map> #include <set> #include <sstream> #include <iomanip> using namespace std; typedef long long ll; typedef vector<long long> VI; typedef unsigned long long ull; const ll inff = 0x3f3f3f3f3f3f3f3f; const ll mod=1e9; #define FOR(i,a,b) for(int i(a);i<=(b);++i) #define FOL(i,a,b) for(int i(a);i>=(b);--i) #define SZ(x) ((long long)(x).size()) #define REW(a,b) memset(a,b,sizeof(a)) #define inf int(0x3f3f3f3f) #define si(a) scanf("%d",&a) #define sl(a) scanf("%I64d",&a) #define sd(a) scanf("%lf",&a) #define ss(a) scanf("%s",a) #define pb push_back #define eps 1e-6 #define lc d<<1 #define rc d<<1|1 #define Pll pair<ll,ll> #define P pair<int,int> #define pi acos(-1) ll powmod(ll a,ll b) ll res=1ll; while(b) if(b&1) res=res*a%mod; a=a*a%mod,b>>=1; return res; namespace linear_seq const int N=10010; using int64 = long long; using vec = std::vector<int64>; ll res[N],base[N],_c[N],_md[N]; vector<int> Md; void mul(ll *a,ll *b,int k) FOR(i,0,k+k-1) _c[i]=0; FOR(i,0,k-1) if (a[i]) FOR(j,0,k-1) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod; for (int i=k+k-1;i>=k;i--) if (_c[i]) FOR(j,0,SZ(Md)-1) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod; FOR(i,0,k-1) a[i]=_c[i]; int 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; int k=SZ(a); assert(SZ(a)==SZ(b)); FOR(i,0,k-1) _md[k-1-i]=-a[i];_md[k]=1; Md.clear(); FOR(i,0,k-1) if (_md[i]!=0) Md.push_back(i); FOR(i,0,k-1) 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(j,0,SZ(Md)-1) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod; FOR(i,0,k-1) 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(n,0,SZ(s)-1) ll d=0; FOR(i,0,L) 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); FOR(i,0,SZ(B)-1) 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); FOR(i,0,SZ(B)-1) C[i+m]=(C[i+m]+c*B[i])%mod; ++m; return C; static void extand(vec &a, size_t d, int64 value = 0) if (d <= a.size()) return; a.resize(d, value); static void exgcd(int64 a, int64 b, int64 &g, int64 &x, int64 &y) if (!b) x = 1, y = 0, g = a; else exgcd(b, a % b, g, y, x); y -= x * (a / b); static int64 crt(const vec &c, const vec &m) int n = c.size(); int64 M = 1, ans = 0; for (int i = 0; i < n; ++i) M *= m[i]; for (int i = 0; i < n; ++i) int64 x, y, g, tm = M / m[i]; exgcd(tm, m[i], g, x, y); ans = (ans + tm * x * c[i] % M) % M; return (ans + M) % M; static vec ReedsSloane(const vec &s, int64 mod) auto inverse = [](int64 a, int64 m) int64 d, x, y; exgcd(a, m, d, x, y); return d == 1 ? (x % m + m) % m : -1; ; auto L = [](const vec &a, const vec &b) int da = (a.size() > 1 || (a.size() == 1 && a[0])) ? a.size() - 1 : -1000; int db = (b.size() > 1 || (b.size() == 1 && b[0])) ? b.size() - 1 : -1000; return std::max(da, db + 1); ; auto prime_power = [&](const vec &s, int64 mod, int64 p, int64 e) // linear feedback shift register mod p^e, p is prime std::vector<vec> a(e), b(e), an(e), bn(e), ao(e), bo(e); vec t(e), u(e), r(e), to(e, 1), uo(e), pw(e + 1);; pw[0] = 1; for (int i = pw[0] = 1; i <= e; ++i) pw[i] = pw[i - 1] * p; for (int64 i = 0; i < e; ++i) a[i] = pw[i], an[i] = pw[i]; b[i] = 0, bn[i] = s[0] * pw[i] % mod; t[i] = s[0] * pw[i] % mod; if (t[i] == 0) t[i] = 1, u[i] = e; else for (u[i] = 0; t[i] % p == 0; t[i] /= p, ++u[i]); for (size_t k = 1; k < s.size(); ++k) for (int g = 0; g < e; ++g) if (L(an[g], bn[g]) > L(a[g], b[g])) ao[g] = a[e - 1 - u[g]]; bo[g] = b[e - 1 - u[g]]; to[g] = t[e - 1 - u[g]]; uo[g] = u[e - 1 - u[g]]; r[g] = k - 1; a = an, b = bn; for (int o = 0; o < e; ++o) int64 d = 0; for (size_t i = 0; i < a[o].size() && i <= k; ++i) d = (d + a[o][i] * s[k - i]) % mod; if (d == 0) t[o] = 1, u[o] = e; else for (u[o] = 0, t[o] = d; t[o] % p == 0; t[o] /= p, ++u[o]); int g = e - 1 - u[o]; if (L(a[g], b[g]) == 0) extand(bn[o], k + 1); bn[o][k] = (bn[o][k] + d) % mod; else int64 coef = t[o] * inverse(to[g], mod) % mod * pw[u[o] - uo[g]] % mod; int m = k - r[g]; extand(an[o], ao[g].size() + m); extand(bn[o], bo[g].size() + m); for (size_t i = 0; i < ao[g].size(); ++i) an[o][i + m] -= coef * ao[g][i] % mod; if (an[o][i + m] < 0) an[o][i + m] += mod; while (an[o].size() && an[o].back() == 0) an[o].pop_back(); for (size_t i = 0; i < bo[g].size(); ++i) bn[o][i + m] -= coef * bo[g][i] % mod; if (bn[o][i + m] < 0) bn[o][i + m] -= mod; while (bn[o].size() && bn[o].back() == 0) bn[o].pop_back(); return std::make_pair(an[0], bn[0]); ; std::vector<std::tuple<int64, int64, int>> fac; for (int64 i = 2; i * i <= mod; ++i) if (mod % i == 0) int64 cnt = 0, pw = 1; while (mod % i == 0) mod /= i, ++cnt, pw *= i; fac.emplace_back(pw, i, cnt); if (mod > 1) fac.emplace_back(mod, mod, 1); std::vector<vec> as; size_t n = 0; for (auto &&x: fac) int64 mod, p, e; vec a, b; std::tie(mod, p, e) = x; auto ss = s; for (auto &&x: ss) x %= mod; std::tie(a, b) = prime_power(ss, mod, p, e); as.emplace_back(a); n = std::max(n, a.size()); vec a(n), c(as.size()), m(as.size()); for (size_t i = 0; i < n; ++i) for (size_t j = 0; j < as.size(); ++j) m[j] = std::get<0>(fac[j]); c[j] = i < as[j].size() ? as[j][i] : 0; a[i] = crt(c, m); return a; ll gao(VI a,ll n,ll mod,bool prime=true) VI c; if(prime) c=BM(a); //素数使用BM else c=ReedsSloane(a,mod); //合数使用ReedsSloane c.erase(c.begin()); FOR(i,0,SZ(c)-1) c[i]=(mod-c[i])%mod; return solve(n,c,VI(a.begin(),a.begin()+SZ(c))); ; ll qpow(ll a,ll b, ll mod) ll res=1; while(b) if(b&1) res=res*a%mod; a=a*a%mod,b>>=1; return res; vector<ll>tmp; int n, m; int main() scanf("%d%d", &n,&m); ll a = 0, b = 1, c, sum = 1; tmp.push_back(0);tmp.push_back(1); for(int i = 2;i <= 2*57;i++) c = (a + b) % mod; a = b; b = c; sum = (sum + qpow(c, m, mod)) % mod; tmp.push_back(sum); //printf("%lld\\n", c); //for(int i = 0;i <= 2*m;i++) printf("%lld\\n", tmp[i]); printf("%lld\\n", linear_seq::gao(tmp, n, mod, false));
Code From:https://www.cnblogs.com/Profish/p/9738143.html
以上是关于BM递推杜教版扩展的主要内容,如果未能解决你的问题,请参考以下文章