题目大意:求一个满足$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. Loadrunner 性能指标

    https://wenku.baidu.com/view/bf395a1db7360b4c2e3f64ca.html 希望能记住最好记住吧,这个很重要的. qq,979506750多交流

  2. java多线程相关代码

    1.创建线程的三种方式 使用Thread package com.wpbxx.test; //1.自定义一个类,继承java.lang包下的Thread类 class MyThread extends ...

  3. AutoResetEvent 方法名称设计缺陷

    这个类和方法,让人乍一读是读不明白的.不能通过方法名称明白其含义.所以它的方法名称设计是欠考虑. 应该类似于这样: public static class MyAutoResetEvent { pub ...

  4. 搭建gitpage博客

    http://blog.csdn.net/jzooo/article/details/46781805

  5. java判断字符串编码

    是 public static String getEncoding(String str){ String encoding = "UTF-8"; try { if (str.e ...

  6. 奔跑吧DKY——团队Scrum冲刺阶段-Day 6

    今日完成任务 谭鑫:制作相应动画人物,并实现人物动画 黄宇塘:制作相应动画人物,并实现人物动画,制作背景图 赵晓海:制作相应动画人物,并实现人物动画 方艺雯:制作相应动画人物,并实现人物动画,编写博客 ...

  7. Sqlite数据库初步的了解

    转载与:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2013/0714/1438.html    来自:泡在网上的日子. 和其他数据库一 ...

  8. CMD命令操作符

    cmd                   command的缩写,是windows环境下的虚拟DOS窗口,提供有DOS命令,功能强大 mstsc                 远程 inetmgr  ...

  9. 【Coursera】线性回归和逻辑回归

    一.线性回归 1.批量梯度下降法 每次对参数进行一次迭代时,都要扫描一遍输入全集 算法可以收敛到局部最优值 当迭代多次之后,每次迭代参数的改变越小 2.随机梯度下降法 对于一个输入样本,对参数进行一次 ...

  10. Unity3D游戏开发——显示物品的仓库UI

    访问仓库物品列表的方法 为了在UI中显示物品列表,我们需要给InventoryManager添加两个能够访问它的公有方法: 代码: ··· public List<string> GetI ...