Berlekamp-Massey算法,常简称为BM算法,是用来求解一个数列的最短线性递推式的算法。
BM算法可以在O(N2)的时间内求解一个长度为N的数列的最短线性递推式。
12124
#include
using namespace std;
#define rep(i,a,n) for(int i=a;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)));
}
}
int main() {
ll t;
ll nnn;
VI a;
a.push_back(3);
a.push_back(9);
a.push_back(20);
a.push_back(46);
a.push_back(106);
a.push_back(244);
a.push_back(560);
a.push_back(1286);
a.push_back(2956);
a.push_back(6794);
scanf("%lld",&t);
while(t--) {
scanf("%lld",&nnn);
printf("%lld\n",linear_seq::gao(a,nnn-1));
}
}
13704
#include
using namespace std;
#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))
const int64_t Mod (1000000000) ;
int64_t powEx(int64_t base,int64_t n,int64_t Mod = ::Mod )
{
int64_t ret(1);
while(n){
if(n&1) ret = ret*base%Mod ;
base = base * base %Mod ;
n >>= 1 ;
}
return ret % Mod ;
}
class Linear_Seq
{
using VI = vector<int64_t> ;
public:
static const int N=10010;
int64_t res[N],base[N],c[N],md[N];
vector<int> Md;
inline void mulEx(int64_t *a,int64_t *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<Md.size();++j)
c[i-k+Md[j]]=(c[i-k+Md[j]]-c[i]*md[Md[j]])%Mod;
copy(c,c+k,a) ;
}
int solve(int64_t n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
int64_t ans(0),cnt(0);
int k(a.size());
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]) Md.push_back(i);
for(int i(0);i<k;++i) res[i] = base[i] = 0;
res[0]=1;
while ((1LL<<cnt)<=n) ++ cnt;
for (int p(cnt);~p;-- p) {
mulEx(res,res,k);
if ((n>>p)&1) {
for (int i(k-1);~i;--i) res[i+1]=res[i];res[0]=0;
for(int j(0);j<Md.size();++j)
res[Md[j]]=(res[Md[j]]-res[k]*md[Md[j]])%Mod;
}
}
for(int i(0);i<k;++i) ans=(ans+res[i]*b[i])%Mod;
return ans+(ans<0?Mod:0);
}
VI BM(VI s) {
VI ret(1,1),B(1,1);
int L(0),m(1),b(1);
for(int n(0);n<s.size();++n) {
int64_t d(0);
for(int i(0);i<=L;++i)
d=(d+(int64_t)ret[i]*s[n-i])%Mod;
if (!d) ++m;
else if (2*L<=n) {
VI T=ret;
int64_t c(Mod-d*powEx(b,Mod-2)%Mod);
while (ret.size()<B.size()+m) ret.push_back(0);
for (int i(0);i<B.size();++i)
ret[i+m]=(ret[i+m]+c*B[i])%Mod;
L=n+1-L; B=T; b=d; m=1;
} else {
int64_t c(Mod-d*powEx(b,Mod-2)%Mod);
while (ret.size()<B.size()+m) ret.push_back(0);
for(int i(0);i<B.size();++i)
ret[i+m]=(ret[i+m]+c*B[i])%Mod;
++m;
}
}
return ret;
}
inline static void extand(VI &a, size_t d, int64_t value = 0) {
if (d <= a.size()) return;
a.resize(d, value);
}
inline static int64_t gcdEx(int64_t a, int64_t b, int64_t&x, int64_t& y)
{
if(!b) {x=1;y=0;return a;}
int64_t d = gcdEx(b,a%b,y,x);
y -= (a/b)*x;
return d;
}
static int64_t CRT(const VI &c, const VI &m) {
int n(c.size());
int64_t M(1), ans(0);
for (int i = 0; i < n; ++i) M *= m[i];
for (int i = 0; i < n; ++i) {
int64_t x,y,tM(M / m[i]);
gcdEx(tM, m[i], x, y);
ans = (ans + tM * x * c[i] % M) % M;
}
return (ans + M) % M;
}
static VI ReedsSloane(const VI &s, int64_t Mod) {
auto Inv = [](int64_t a, int64_t Mod) {
int64_t x, y;
return gcdEx(a, Mod, x, y)==1?(x%Mod+Mod)%Mod:-1;
};
auto L = [](const VI &a, const VI &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 max(da, db + 1);
};
auto prime_power = [&](const VI &s, int64_t Mod, int64_t p, int64_t e) {
// linear feedback shift register Mod p^e, p is prime
vector<VI> a(e), b(e), an(e), bn(e), ao(e), bo(e);
VI 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_t 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]) {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_t 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);t[o]/=p ,++u[o]);
int g (e-1-u[o]);
if (!L(a[g], b[g])) {
extand(bn[o], k + 1);
bn[o][k] = (bn[o][k] + d) % Mod;
} else {
int64_t coef = t[o]*Inv(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()) 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()) bn[o].pop_back();
}
}
}
}
return make_pair(an[0], bn[0]);
};
vector<tuple<int64_t, int64_t, int> > fac;
for (int64_t i(2); i*i <= Mod; ++i)
if (!(Mod % i)) {
int64_t cnt(0),pw(1);
while (!(Mod % i)) {Mod /= i; ++cnt; pw *= i;}
fac.emplace_back(pw, i, cnt);
}
if (Mod > 1) fac.emplace_back(Mod, Mod, 1);
vector<VI> as;
size_t n = 0;
for (auto &&x: fac) {
int64_t Mod, p, e;
VI 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 = max(n, a.size());
}
VI 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;
}
int64_t solve(VI a,int64_t n,int64_t Mod,bool prime=true) {
VI c;
if(prime) c = BM(a);
else c = ReedsSloane(a,Mod);
c.erase(c.begin());
for(int i(0);i<c.size();++i) c[i] = (Mod-c[i])%Mod;
return solve(n,c,VI(a.begin(),a.begin()+c.size()));
}
}BM;
typedef long long ll;
ll sum;
ll a[1005];
int main()
{
cin.tie(0);
cout.tie(0);
int64_t n, m;
cin >> n >> m;
a[0]=a[1]=1;
vector<int64_t> f;//({0, 1});
//f.push_back(0);
f.push_back(1);
f.push_back(2);
sum=2;
for (int i = 2; i < 1000; i++)
{
a[i]=(a[i-1]+a[i-2])%Mod;
sum =(sum+powEx(a[i],m,Mod))%Mod;
f.push_back(sum); //这里是因为题意要求出和的值所以导入数列和
}
printf("%lld\n",BM.solve(f,n-1,Mod,false)); //false-模数为合数
return 0;
}
代码来源
#include
using namespace std;
const int MAXN = 2005;
const double eps = 1e-8;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
int cnt, fail[MAXN];
double val[MAXN], delta[MAXN];
vector <double> ans[MAXN];
int main() {
int n; read(n);
for (int i = 1; i <= n; i++)
scanf("%lf", &val[i]);
for (int i = 1; i <= n; i++) {
double tmp = val[i];
for (unsigned j = 0; j < ans[cnt].size(); j++)
tmp -= ans[cnt][j] * val[i - j - 1];
delta[i] = tmp;
if (fabs(tmp) <= eps) continue;
fail[cnt] = i;
if (cnt == 0) {
ans[++cnt].resize(i);
continue;
}
double mul = delta[i] / delta[fail[cnt - 1]];
cnt++; ans[cnt].resize(i - fail[cnt - 2] - 1);
ans[cnt].push_back(mul);
for (unsigned j = 0; j < ans[cnt - 2].size(); j++)
ans[cnt].push_back(ans[cnt - 2][j] * -mul);
if (ans[cnt].size() < ans[cnt - 1].size()) ans[cnt].resize(ans[cnt - 1].size());
for (unsigned j = 0; j < ans[cnt - 1].size(); j++)
ans[cnt][j] += ans[cnt - 1][j];
}
for (unsigned i = 0; i < ans[cnt].size(); i++)
cout << ans[cnt][i] << ' ';
return 0;
}