0
点赞
收藏
分享

微信扫一扫

【模板】线性递推

【模板】线性递推_多项式
【模板】线性递推_#define_02
首先暴力的矩阵乘是 【模板】线性递推_i++_03
引入概念:特征多项式
【模板】线性递推_#define_04
【模板】线性递推_i++_05 为单位矩阵
然后对于这道题来讲,转移矩阵是这样的
【模板】线性递推_#define_06
【模板】线性递推_#define_07
对第一行展开然后分别求行列式
【模板】线性递推_i++_08
然后发现去除第一行和某一列后主对角线都是满的,消成下三角矩阵,行列式是主对角线的乘积
【模板】线性递推_i++_09
然后由 【模板】线性递推_#define_10 定理
【模板】线性递推_#define_11,一个巧妙的伪证是 【模板】线性递推_#define_12
【模板】线性递推_i++_13,即 【模板】线性递推_#define_14
又因为 【模板】线性递推_#define_11 ,所以 【模板】线性递推_多项式_16
看看求的是什么,是向量 【模板】线性递推_#define_17,乘上 【模板】线性递推_#define_18 的第 k 列,令【模板】线性递推_多项式_19 的各项系数为 【模板】线性递推_多项式_20
【模板】线性递推_多项式_21
初始向量 【模板】线性递推_#define_17 乘上转移矩阵 【模板】线性递推_多项式_23 次,即为给出的 【模板】线性递推_i++_24
于是 【模板】线性递推_多项式_25
【模板】线性递推_多项式_20即特征多项式的系数可以用 【模板】线性递推_#define_18【模板】线性递推_i++_09 多项式取模得出
复杂度 【模板】线性递推_i++_29
主要的思想就是不必求出 【模板】线性递推_#define_18,将【模板】线性递推_#define_18 转换成【模板】线性递推_i++_32
并且也不求 【模板】线性递推_i++_33,而是用初始向量去乘它【模板】线性递推_i++_34,得到了我们想要的答案

#include<bits/stdc++.h>
#define N 400050
using namespace std;
typedef long long ll;
const int Mod = 998244353, G = 3;
ll add(ll a, ll b){ return a + b >= Mod ? a + b - Mod : a + b;}
ll mul(ll a, ll b){ return a * b % Mod;}
ll power(ll a, ll b){ ll ans = 1;
for(;b;b>>=1){if(b&1) ans = mul(ans, a); a = mul(a, a);}
return ans;
}
ll inv[N]; int n, k;
#define poly vector<ll>
#define C 20
poly w[C + 1];
int up, bit, rev[N]; ll a[N];
void Init(int len){ up = 1, bit = 0;
while(up < len) up <<= 1, bit++;
for(int i = 0; i < up; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void prework(){
inv[0] = inv[1] = 1;
for(int i = 2; i <= N-50; i++) inv[i] = mul(Mod-Mod/i, inv[Mod%i]);
for(int i = 1; i <= C; i++) w[i].resize(1<<(i-1));
ll wn = power(G, (Mod-1)/(1<<C)); w[C][0] = 1;
for(int i = 1; i < (1<<(C-1)); i++) w[C][i] = mul(w[C][i-1], wn);
for(int i = C-1; i; i--)
for(int j = 0; j < (1<<(i-1)); j++)
w[i][j] = w[i+1][j<<1];
}
void NTT(poly &a, int flag){
for(int i = 0; i < up; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int i = 1, l = 1; i < up; i <<= 1, l++)
for(int j = 0; j < up; j += (i<<1))
for(int k = 0; k < i; k++){
ll x = a[k + j], y = mul(w[l][k], a[k + j + i]);
a[k + j] = add(x, y); a[k + j + i] = add(x, Mod-y);
}
if(flag == -1){
reverse(a.begin() + 1, a.begin() + up);
for(int i = 0; i < up; i++) a[i] = mul(a[i], inv[up]);
}
}
poly operator * (poly a, poly b){
int len = a.size() + b.size() - 1;
Init(len); a.resize(up); b.resize(up);
NTT(a, 1); NTT(b, 1);
for(int i = 0; i < up; i++) a[i] = mul(a[i], b[i]);
NTT(a, -1); a.resize(len); return a;
}
poly Inv(poly a, int len){
poly b(1, power(a[0], Mod - 2)), c;
for(int lim = 4; lim < (len << 2); lim <<= 1){
Init(lim); c = a; c.resize(lim >> 1);
c.resize(up); b.resize(up); NTT(c, 1); NTT(b, 1);
for(int i = 0; i < up; i++) b[i] = mul(b[i], add(2, Mod - mul(b[i], c[i])));
NTT(b, -1); b.resize(lim >> 1);
} b.resize(len); return b;
}
poly operator - (poly a, poly b){
poly c; int len = max(a.size(), b.size()); c.resize(len);
a.resize(len); b.resize(len);
for(int i = 0; i < len; i++) c[i] = add(a[i], Mod - b[i]);
return c;
}
poly operator / (poly a, poly b){
int lim = 1, len = a.size() - b.size() + 1;
reverse(a.begin(), a.end()); reverse(b.begin(), b.end());
while(lim <= len) lim <<= 1;
b = Inv(b, lim); b.resize(len);
a = a * b; a.resize(len);
reverse(a.begin(), a.end());
return a;
}
poly operator % (poly a, poly b){
int len = a.size() - b.size() + 1;
if(len < 0) return a;
poly c = a - (a / b) * b;
c.resize(b.size() - 1); return c;
}
int main(){
scanf("%d%d", &n, &k); prework();
poly f(k + 1);
for(int i = 1; i <= k; i++) scanf("%lld", &f[k - i]), f[k - i] = Mod - (f[k - i] % Mod + Mod) % Mod;
f[k] = 1;
for(int i = 0; i < k; i++) scanf("%lld", &a[i]), a[i] = (a[i] % Mod + Mod) % Mod;
poly res, g;
res.resize(k + 1); res[0] = 1;
g.resize(k + 1); g[1] = 1;
for(;n;n>>=1, g = g * g % f) if(n & 1) res = res * g % f;
ll ans = 0;
for(int i = 0; i < res.size(); i++) ans = add(ans, mul(res[i], a[i]));
cout << ans;
return 0;
}


举报

相关推荐

0 条评论