题目大意:求一个满足$k$阶齐次线性递推数列$a_i$的第$n$项。

即:$a_n=\sum\limits_{i=1}^{k}f_i \times a_{n-i}$

解:线性齐次递推,先见洛谷题解,下回再补

卡点:数组大小计算错误,求逆中途计算时忘记加$mod$等

C++ Code:(这份全部是板子,可以用来测试,但是常数巨大)

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define maxk 32010
#define maxn 131072
const int mod = 998244353; #define mul(x, y) static_cast<long long> (x) * (y) % mod namespace Math {
inline int pw(int base, int p) {
static int res;
for (res = 1; p; p >>= 1, base = mul(base, base)) if (p & 1) res = mul(res, base);
return res;
}
inline int inv(int x) { return pw(x, mod - 2); }
}
inline void reduce(int &x) { x += x >> 31 & mod; } namespace Poly {
#define N maxn
int lim, s, rev[N], Wn[N];
inline void init(const int n) {
lim = 1, s = -1; while (lim < n) lim <<= 1, ++s;
for (register int i = 1; i < lim; ++i) rev[i] = rev[i >> 1] >> 1 | (i & 1) << s;
const int t = Math::pw(3, (mod - 1) / lim);
*Wn = 1; for (register int *i = Wn + 1; i != Wn + lim; ++i) *i = mul(*(i - 1), t);
}
inline void FFT(int *A, const int op = 1) {
for (register int i = 1; i < lim; ++i) if (i < rev[i]) std::swap(A[i], A[rev[i]]);
for (register int mid = 1; mid < lim; mid <<= 1) {
const int t = lim / mid >> 1;
for (register int i = 0; i < lim; i += mid << 1)
for (register int j = 0; j < mid; ++j) {
const int X = A[i + j], Y = mul(A[i + j + mid], Wn[t * j]);
reduce(A[i + j] += Y - mod), reduce(A[i + j + mid] = X - Y);
}
}
if (!op) {
const int ilim = Math::inv(lim);
for (register int *i = A; i != A + lim; ++i) *i = mul(*i, ilim);
std::reverse(A + 1, A + lim);
}
} void INV(int *A, int *B, int n) {
if (n == 1) { *B = Math::inv(*A); return ; }
static int C[N], D[N];
const int len = n + 1 >> 1;
INV(A, B, len), init(len * 3);
std::memcpy(C, A, n << 2), std::memset(C + n, 0, lim - n << 2);
std::memcpy(D, B, len << 2), std::memset(D + len, 0, lim - len << 2);
FFT(C), FFT(D);
for (int i = 0; i < lim; ++i) D[i] = (2 - mul(D[i], C[i]) + mod) * D[i] % mod;
FFT(D, 0);
std::memcpy(B + len, D + len, n - len << 2);
}
void DIV(int *A, int *B, int *Q, int n, int m) {
static int C[N], D[N], E[N];
const int len = n - m + 1;
std::reverse_copy(A, A + n, C), std::reverse_copy(B, B + m, D);
INV(D, E, len), init(len << 1);
std::memset(C + len, 0, lim - len << 2), std::memset(E + len, 0, lim - len << 2);
FFT(C), FFT(E);
for (int i = 0; i < lim; ++i) Q[i] = mul(C[i], E[i]);
FFT(Q, 0), std::reverse(Q, Q + len);
}
void DIV_MOD(int *A, int *B, int *Q, int *R, int n, int m) {
static int C[N], D[N], E[N];
const int len = n - m + 1;
DIV(A, B, Q, n, m), init(n << 1);
std::memcpy(C, A, n << 2), std::memset(C + n, 0, lim - n << 2);
std::memcpy(D, B, m << 2), std::memset(D + m, 0, lim - m << 2);
std::memcpy(E, Q, len << 2), std::memset(E + len, 0, lim - len << 2);
FFT(C), FFT(D), FFT(E);
for (int i = 0; i < lim; ++i) reduce(R[i] = C[i] - mul(D[i], E[i]));
FFT(R, 0);
}
void MOD(int *A, int *B, int m) {
static int Q[N], R[N];
DIV_MOD(A, B, Q, R, (m << 1) - 1, m + 1);
std::memcpy(A, R, m << 2);
} void POW(int *base, int p, int *Mod, int m) {
static int res[N], T[N];
res[0] = 1;
while (p) {
if (p & 1) {
init(m << 1), std::memset(res + m, 0, lim - m << 2);
std::memcpy(T, base, m << 2), std::memset(T + m, 0, lim - m << 2);
FFT(T), FFT(res);
for (int i = 0; i < lim; ++i) res[i] = mul(res[i], T[i]);
FFT(res, 0); MOD(res, Mod, m);
}
p >>= 1;
if (p) {
init(m << 1), std::memset(base + m, 0, lim - m << 2);
FFT(base);
for (int i = 0; i < lim; ++i) base[i] = mul(base[i], base[i]);
FFT(base, 0), MOD(base, Mod, m);
}
}
std::memcpy(base, res, m << 2);
} int solve(int *f, int *a, int n, int k) { //a为递推式0~k-1项,f为转移数组1~k项
static int A[maxn], G[maxn];
for (int i = 1; i <= k; ++i) reduce(G[k - i] = -f[i]);
G[k] = A[1] = 1;
Poly::POW(A, n, G, k);
int ans = 0;
for (int i = 0; i < k; ++i) reduce(ans += mul(A[i], a[i]) - mod);
return ans;
}
#undef N
} int n, k;
int f[maxk], a[maxk];
int main()
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
std::cin >> n >> k;
for (int i = 1; i <= k; ++i) std::cin >> f[i];
for (int i = 0; i < k; ++i) std::cin >> a[i], reduce(a[i]);
std::cout << Poly::solve(f, a, n, k) << '\n';
return 0;
}

 

发现取模的那一个多项式是一定的,可以预处理出它的逆元以及点值表达式等,减小常数。

C++ Code:(这一份常数还算正常)

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define maxk 32010
#define maxn 65536
const int mod = 998244353; #define mul(x, y) static_cast<long long> (x) * (y) % mod namespace Math {
inline int pw(int base, int p) {
static int res;
for (res = 1; p; p >>= 1, base = mul(base, base)) if (p & 1) res = mul(res, base);
return res;
}
inline int inv(int x) { return pw(x, mod - 2); }
}
inline void reduce(int &x) { x += x >> 31 & mod; } namespace Poly {
#define N maxn
int lim, s, rev[N], Wn[N];
inline void init(const int n) {
lim = 1, s = -1; while (lim < n) lim <<= 1, ++s;
for (register int i = 1; i < lim; ++i) rev[i] = rev[i >> 1] >> 1 | (i & 1) << s;
const int t = Math::pw(3, (mod - 1) / lim);
*Wn = 1; for (register int *i = Wn + 1; i != Wn + lim; ++i) *i = mul(*(i - 1), t);
}
inline void FFT(int *A, const int op = 1) {
for (register int i = 1; i < lim; ++i) if (i < rev[i]) std::swap(A[i], A[rev[i]]);
for (register int mid = 1; mid < lim; mid <<= 1) {
const int t = lim / mid >> 1;
for (register int i = 0; i < lim; i += mid << 1)
for (register int j = 0; j < mid; ++j) {
const int X = A[i + j], Y = mul(A[i + j + mid], Wn[t * j]);
reduce(A[i + j] += Y - mod), reduce(A[i + j + mid] = X - Y);
}
}
if (!op) {
const int ilim = Math::inv(lim);
for (register int *i = A; i != A + lim; ++i) *i = mul(*i, ilim);
std::reverse(A + 1, A + lim);
}
} void INV(int *A, int *B, int n) {
if (n == 1) { *B = Math::inv(*A); return ; }
static int C[N], D[N];
const int len = n + 1 >> 1;
INV(A, B, len), init(len * 3);
std::memcpy(C, A, n << 2), std::memset(C + n, 0, lim - n << 2);
std::memcpy(D, B, len << 2), std::memset(D + len, 0, lim - len << 2);
FFT(C), FFT(D);
for (int i = 0; i < lim; ++i) D[i] = (2 - mul(D[i], C[i]) + mod) * D[i] % mod;
FFT(D, 0);
std::memcpy(B + len, D + len, n - len << 2);
} int G[N], INVG[N];
void DIV(int *A, int *Q, int n, int m) {
static int C[N];
const int len = n - m + 1;
std::reverse_copy(A, A + n, C), std::memset(C + len, 0, lim - len << 2);
FFT(C);
for (int i = 0; i < lim; ++i) Q[i] = mul(C[i], INVG[i]);
FFT(Q, 0), std::reverse(Q, Q + len);
}
void DIV_MOD(int *A, int *R, int n, int m) {
static int Q[N];
const int len = n - m + 1;
DIV(A, Q, n, m), std::memset(Q + len, 0, lim - len << 2);
FFT(Q);
for (int i = 0; i < lim; ++i) R[i] = mul(G[i], Q[i]);
FFT(R, 0);
for (int i = 0; i < m; ++i) reduce(R[i] = A[i] - R[i]);
} void POW(int *A, int p, int m) {
if (!p) return ;
POW(A, p >> 1, m);
static int T[N];
std::memcpy(T, A, m << 2), std::memset(T + m, 0, lim - m << 2);
FFT(T);
for (int i = 0; i < lim; ++i) T[i] = mul(T[i], T[i]);
FFT(T, 0);
if (p & 1) {
for (int i = 2 * m - 1; ~i; --i) T[i] = T[i - 1];
T[0] = 0;
}
DIV_MOD(T, A, 2 * m, m + 1);
} int solve(int *f, int *a, int n, int k) { //a为递推式0~k-1项,f为转移数组1~k项
static int A[maxn], B[maxn];
for (int i = 1; i <= k; ++i) reduce(G[k - i] = -f[i]);
G[k] = A[0] = 1;
std::reverse_copy(G, G + k + 1, B), B[k] = 0;
INV(B, INVG, k), init(k << 1);
FFT(G), FFT(INVG);
Poly::POW(A, n, k);
int ans = 0;
for (int i = 0; i < k; ++i) reduce(ans += mul(A[i], a[i]) - mod);
return ans;
}
#undef N
} int n, k;
int f[maxk], a[maxk];
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
std::cin >> n >> k;
for (int i = 1; i <= k; ++i) std::cin >> f[i];
for (int i = 0; i < k; ++i) std::cin >> a[i], reduce(a[i]);
std::cout << Poly::solve(f, a, n, k) << '\n';
return 0;
}

  

 

[洛谷P4723]【模板】线性递推的更多相关文章

  1. 洛谷 P5110 块速递推

    题目大意: 给定一个数列a满足递推式 \(An=233*an-1+666*an-2,a0=0,a1=1\) 求这个数列第n项模\(10^9+7\)的值,一共有T组询问 \(T<=10^7\) \ ...

  2. 洛谷P1240-诸侯安置+递推非搜索

    诸侯安置 这道题是一题递推题,一开始自己不知道,用了搜索,只过了三个样例: 两两相同的合并, 成 1,1,3,3,5,5........n*2-1; 然后我们会容易发现一种不同与搜索的动态规划做法. ...

  3. [洛谷P3383][模板]线性筛素数-欧拉筛法

    Description 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) Input&Output Input 第一行包含两个正整数N.M,分别表示查询的 ...

  4. 洛谷P5110 块速递推 [分块]

    传送门 思路 显然可以特征根方程搞一波(生成函数太累),得到结果: \[ a_n=\frac 1 {13\sqrt{337}} [(\frac{233+13\sqrt{337}}{2})^n-(\fr ...

  5. 模板 - 线性递推BM

    模数是998244353的话好像NTT可以更快. #include<bits/stdc++.h> using namespace std; typedef long long ll; co ...

  6. [模板]线性递推+BM

    暴力版本: #include<bits/stdc++.h> #define mod 998244353 using namespace std; typedef long long int ...

  7. LG5487 【模板】线性递推+BM算法

    [模板]线性递推+BM算法 给出一个数列 \(P\) 从 \(0\) 开始的前 \(n\) 项,求序列 \(P\) 在\(\bmod~998244353\) 下的最短线性递推式,并在 \(\bmod~ ...

  8. BM求线性递推模板(杜教版)

    BM求线性递推模板(杜教版) BM求线性递推是最近了解到的一个黑科技 如果一个数列.其能够通过线性递推而来 例如使用矩阵快速幂优化的 DP 大概都可以丢进去 则使用 BM 即可得到任意 N 项的数列元 ...

  9. 【模板】BM + CH(线性递推式的求解,常系数齐次线性递推)

    这里所有的内容都将有关于一个线性递推: $f_{n} = \sum\limits_{i = 1}^{k} a_{i} * f_{n - i}$,其中$f_{0}, f_{1}, ... , f_{k ...

  10. 【Luogu4723】线性递推(常系数齐次线性递推)

    [Luogu4723]线性递推(常系数齐次线性递推) 题面 洛谷 题解 板子题QwQ,注意多项式除法那里每个多项式的系数,调了一天. #include<iostream> #include ...

随机推荐

  1. Python 的AES加密与解密-需要安装的模块

    踩雷1: #先导入所需要的包 pip3 install Crypto #再安装pycrtpto pin3 install pycrypto from Crypto.Cipher import AES ...

  2. 用Python做一个翻译软件

    前两天吃了平哥的一波狗粮,他给女朋友写了一个翻译软件,自己真真切切的感受到了程序员的浪漫.在学习requests请求的时候做过类似的Demo,给百度翻译发送一个post请求可以实现任意词组的翻译,利用 ...

  3. IDEA配置maven中央库

    分两步: STEP :配置maven: STEP :配置IDEA.区分默认配置和项目级配置. STEP 1:maven中央库配置 国内常用的maven库主要是阿里云maven库.华为云maven. 其 ...

  4. 一种利用ADO连接池操作MySQL的解决方案(VC++)

    VC++连接MySQL数据库 常用的方式有三种:ADO.mysql++,mysql API ; 本文只讲述ADO的连接方式. 为什么要使用连接池? 对于简单的数据库应用,完全可以先创建一个常连接(此连 ...

  5. 从Web抓取信息

    来源:python编程快速上手——Al Sweigart webbrowser:是 Python 自带的,打开浏览器获取指定页面. requests:从因特网上下载文件和网页. Beautiful S ...

  6. 在NodeJS中使用Redis缓存数据

    Redis数据库采用极简的设计思想,最新版的源码包还不到2Mb.其在使用上也有别于一般的数据库. node_redis redis驱动程序多使用 node_redis 此模块可搭载官方的 hiredi ...

  7. JQuery ajax请求struts action实现异步刷新的小实例

    这个样例是用JQuery ajax和struts来做的一个小样例,在这个样例中采用两种方式将java Util中的list转换成支json的格式,第一种是用json-lib.jar这个jar包来转换, ...

  8. Vue 入门之概念

    Vue 简介 Vue 是一个前端的双向绑定类的框架,发音[读音 /vjuː/, 类似于 [view].新的 Vue 版本参考了 React 的部分设计,当然也有自己独特的地方,比如 Vue 的单文件组 ...

  9. 我眼中的PD(产品狗)

    以下内容可能引起您的不适(前方高能),请先移步科普: 产品经理为什么会存在? 本猿 -> web程序属 -> 前端开发种,从大森林迁徙到了小草原: 小草原物种稀缺,除了 程序猿,很难见到诸 ...

  10. BugPhobia回顾篇章:团队Alpha阶段工作分析

    0x00:序言 1 universe, 9 planets, 204 countries,809 islands, 7 seas, and i had the privilege to meet yo ...