zoukankan      html  css  js  c++  java
  • 【模板】常系数齐次线性递推

    题目传送门

    题目大意

    给出 (k,a_{1,2,...,k},f_{1,2,...,k}) ,存在:

    [forall n>kwedge nin mathbb{N},exists a_n=sum_{i=1}^{k}f_ka_{n-k} ]

    给出 (n) ,求出 (a_n)

    (nle 10^9,kle 32000)

    思路

    以下部分借鉴了 BJpers2 的题解

    • 老师我会矩阵快速幂!!!

    恭喜您!您获得了 (Theta(k^3log n)) 的时间复杂度以及 (0) 分的好成绩!!!


    以下是正解。我们考虑从斐波拉契数列入手,我们发现一下事情,假设 (n=5),那么我们可以得到:

    [f_5=f_3+f_4=2f_3+f_2=2f_1+3f_2 ]

    就直接展开就好了。(这里的 (f_i) 指的是第 (i) 位斐波拉契数列,并不是上面转移式里面的值)

    然后我们就发现这个过程其实就是 (x^5)(x^2-x-1) 取模的过程。

    一个感性的解释就是说,这个过程就相当于将一个高次抵消,换成它的展开式。最后的结果肯定就是最后的 (k) 次多项式。

    考虑拓展,然后你发现根据上面的感性解释,其实它的系数就是

    [x^nmod{(x^k-f_1x^{k-1}-f_2x^{k-2}-f_3x^{k-3}-...-f_kx^0)} ]

    然后你发现这个东西直接多项式快速幂即可。时间复杂度 (Theta(klog klog n))

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define SZ(x) ((int)x.size())
    #define Int register int
    #define mod 998244353
    #define MAXN 1000005
    
    int mul (int a,int b){return 1ll * a * b % mod;}
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    int qkpow (int a,int k){
    	int res = 1;for (;k;k >>= 1,a = 1ll * a * a % mod) if (k & 1) res = 1ll * res * a % mod;
    	return res;
    }
    int inv (int x){return qkpow (x,mod - 2);}
    
    typedef vector <int> poly;
    
    int w[MAXN],rev[MAXN];
    
    void init_ntt (){
    	int lim = 1 << 18;
    	for (Int i = 0;i < lim;++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << 17);
    	int Wn = qkpow (3,(mod - 1) / lim);w[lim >> 1] = 1;
    	for (Int i = lim / 2 + 1;i < lim;++ i) w[i] = mul (w[i - 1],Wn);
    	for (Int i = lim / 2 - 1;i;-- i) w[i] = w[i << 1];
    }
    
    void ntt (poly &a,int lim,int type){
    #define G 3
    #define Gi 332748118
    	static int d[MAXN];
    	for (Int i = 0,z = 18 - __builtin_ctz(lim);i < lim;++ i) d[rev[i] >> z] = a[i];
    	for (Int i = 1;i < lim;i <<= 1)
    		for (Int j = 0;j < lim;j += i << 1)
    			for (Int k = 0;k < i;++ k){
    				int x = mul (w[i + k],d[i + j + k]);
    				d[i + j + k] = dec (d[j + k],x),d[j + k] = add (d[j + k],x);
    			}
    	for (Int i = 0;i < lim;++ i) a[i] = d[i] % mod;
    	if (type == -1){
    		reverse (a.begin() + 1,a.begin() + lim);
    		for (Int i = 0,Inv = inv (lim);i < lim;++ i) a[i] = mul (a[i],Inv);
    	}
    #undef G
    #undef Gi 
    }
    
    poly operator + (poly a,poly b){
    	a.resize (max (SZ (a),SZ (b)));
    	for (Int i = 0;i < SZ (b);++ i) a[i] = add (a[i],b[i]);
    	return a;
    }
    
    poly operator - (poly a,poly b){
    	a.resize (max (SZ (a),SZ (b)));
    	for (Int i = 0;i < SZ (b);++ i) a[i] = dec (a[i],b[i]);
    	return a;
    }
    
    poly operator * (poly a,int b){
    	for (Int i = 0;i < SZ (a);++ i) a[i] = mul (a[i],b);
    	return a;
    }
    
    poly operator * (poly a,poly b){
    	int d = SZ (a) + SZ (b) - 1,lim = 1;while (lim < d) lim <<= 1;
    	a.resize (lim),b.resize (lim);
    	ntt (a,lim,1),ntt (b,lim,1);
    	for (Int i = 0;i < lim;++ i) a[i] = mul (a[i],b[i]);
    	ntt (a,lim,-1),a.resize (d);
    	return a;
    }
    
    poly inv (poly a,int n){
    	poly b(1,inv (a[0])),c;
    	for (Int l = 4;(l >> 2) < n;l <<= 1){
    		c.resize (l >> 1);
    		for (Int i = 0;i < (l >> 1);++ i) c[i] = i < n ? a[i] : 0;
    		c.resize (l),b.resize (l);
    		ntt (c,l,1),ntt (b,l,1);
    		for (Int i = 0;i < l;++ i) b[i] = mul (b[i],dec (2,mul (b[i],c[i])));
    		ntt (b,l,-1),b.resize (l >> 1);
    	}
    	b.resize (n);
    	return b;
    }
    
    poly inv (poly a){return inv (a,SZ (a));}
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    poly operator % (poly F,poly G){
    	int n = F.size() - 1,m = G.size() - 1;
    	if (n < m) return F;
    	poly Q;Q.resize (m + 1);
    	for (Int i = 0;i <= m;++ i) Q[i] = G[i];
    	reverse (F.begin(),F.end()),reverse (G.begin(),G.end()),reverse (Q.begin(),Q.end()),Q.resize (n - m + 1),Q = inv (Q) * F,Q.resize (n - m + 1),reverse (Q.begin(),Q.end());
    	reverse (F.begin(),F.end()),reverse (G.begin(),G.end()),Q = G * Q,Q.resize (m),Q = F - Q,Q.resize (m);
    	return Q;	
    }
    
    poly qkpow (int b,poly C){//x^B(mod C) 的答案 
    	poly res(1,1),a;a.push_back (0),a.push_back (1);
    	for (;b;b >>= 1,a = (a * a) % C) if (b & 1) res = (res * a) % C;
    	return res;
    }
    
    int n,k,f[MAXN],a[MAXN];
    poly F,G,Q;
    
    signed main(){
    	init_ntt ();
    	read (n,k);
    	for (Int i = 1;i <= k;++ i) read (f[i]),f[i] = (mod + f[i] % mod) % mod;
    	for (Int i = 0;i < k;++ i) read (a[i]),a[i] = (mod + a[i] % mod) % mod; 
    	G.resize (k + 1);G[k] = 1;
    	for (Int i = 1;i <= k;++ i) G[k - i] = mod - f[i];
    	Q = qkpow (n,G);
    	int ans = 0;for (Int i = 0;i <= k;++ i) ans = add (ans,mul (Q[i],a[i]));
    	write ((ans % mod + mod) % mod),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    7.4 List集合
    vue学习笔记
    javaWEB中web.xml配置文件相关
    maven常用dos命令
    Oracle,sqlserver,mySQl的区别和联系:
    oracle数据库视图,序列,索引的sql语句查看
    java 异常处理
    线程专题
    package、folder和source folder的区别
    Java内存分配之堆、栈和常量池
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13598441.html
Copyright © 2011-2022 走看看