题目大意:求一个满足$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. Post请求和Get请求;@RequestBody和@RequestParam

    1.@RequestBody用于Post请求,接收json数据,例如:@RequestBody User user 例如:@RequestBody Map map .不要用于Get请求. 2.@Req ...

  2. Unity扩展编辑器一

    将Test1脚本挂在摄像机上 ​ 如图展示 ​ 下面我们需要在代码中动态的编辑它,请在你的Project视图中创建一个Editor文件夹,把MyEditor放进Editor文件夹中 ​ 在OnInsp ...

  3. yocto-sumo源码解析(一): oe-init-build-env

    oe-init-build-env是yocto构建环境运行的第一个脚本,通过运行下面的命令: . oe-init-build-env build-arm64 即可对yocto项目进行构建,顾名思义,该 ...

  4. WinDbg使用学习

    拿到软件崩溃之后产生的crash文件,后缀名为dump 使用winDbg的File-----> Open Crash Dump 打开Crash文件 File---------> Symbo ...

  5. Linux 文件搜索命令:find、which、whereis 和 locate

    Linux 提供了许多用于文件搜索的命令,这些命令都很强大,但是也有一些不同之处,这里分别介绍一下. 一.find 命令 find 是最常见和最强大的一个文件搜索命令.使用 find 命令可以在指定目 ...

  6. ansible使用1

    常用软件安装及使用目录   ansible软件2 ### ansible软件部署安装需求#### 01. 需要有epel源 系统yum源(base epel--pip gem) sshpass---e ...

  7. 在js中保存数据

    localStorage: localStorage.setItem("key", "value"); localStorage.getItem("k ...

  8. “北航Clubs” Alpha版发布!

    一.功能 1.获取活动信息: 用户进入网站后,第一眼就可以查看到近期活动 2.查看活动详情 点击活动标题,可以进入活动详情页面 3.注册功能 首页点击注册,输入学号.密码.姓名.手机号即可完成注册 4 ...

  9. java实验2实验报告(20135232王玥)

    实验二 Java面向对象程序设计 一.实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解 ...

  10. 进阶系列(10)—— C#元数据和动态编程

    一.元数据的介绍 元数据是用来描述数据的数据(Data that describes other data).单单这样说,不太好理解,我来举个例子.下面是契诃夫的小说<套中人>中的一段,描 ...