题目大意:求一个满足$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. 《杜增强讲Unity之Tanks坦克大战》5-子弹

    5 子弹 本节的任务是创建子弹的Prefab   image 首先从Model/Shell找到子弹的模型,拖入Hierarchy中,添加刚体组件,所有属性默认值. 添加Capsule Collider ...

  2. BAT面试必备——Java 集合类

    本文首发于我的个人博客:尾尾部落 1. Iterator接口 Iterator接口,这是一个用于遍历集合中元素的接口,主要包含hashNext(),next(),remove()三种方法.它的一个子接 ...

  3. JS如何设置元素样式的方法示例

    <div id="box"></div> <script> var box = document.getElementById("bo ...

  4. Netty源码分析第4章(pipeline)---->第6节: 传播异常事件

    Netty源码分析第四章: pipeline 第6节: 传播异常事件 讲完了inbound事件和outbound事件的传输流程, 这一小节剖析异常事件的传输流程 首先我们看一个最最简单的异常处理的场景 ...

  5. 高可用OpenStack(Queen版)集群-3.高可用配置(pacemaker&haproxy)

    参考文档: Install-guide:https://docs.openstack.org/install-guide/ OpenStack High Availability Guide:http ...

  6. 简介几种系统调用函数:write、read、open、close、ioctl

    在 Linux 中,一切(或几乎一切)都是文件,因此,文件操作在 Linux 中是十分重要的,为此,Linux 系统直接提供了一些函数用于对文件和设备进行访问和控制,这些函数被称为系统调用(sysca ...

  7. 查看、生成 SSH 密钥用于安全登陆

    SSH 可以用来登陆服务器,远程执行命令,并用强加密算法编码保护通信安全,目前广泛应用于远程命令控制.文件加密传输等方面.SSH 登陆服务器的方法一般有两种:密码登陆和密钥登陆. 在受信任的设备上使用 ...

  8. Redis Jedis简介

    Redis是一种基于内存类型的数据存储工具 Jedis是一个用java写的Redis数据库操作的客户端,通过Jedis,可以很方便的对redis数据库进行操作.Jedis通过Jedis Pool进行R ...

  9. SQL中读取Excel 以及 bpc语言

    --开启导入功能 reconfigure reconfigure --允许在进程中使用ACE.OLEDB.12 --允许动态参数 EXEC master.dbo.sp_MSset_oledb_prop ...

  10. oracle安装出错/runInstaller

    http://blog.csdn.net/yabingshi_tech/article/details/48313955 http://www.cnblogs.com/lihaozy/archive/ ...