LOJ6183 看无可看 (分治FFT)(生成函数)(特征方程)

传送门

首先题目给出的递推式的特征方程是 λ 2 − 2 ∗ λ − 3 = 0 \lambda^2-2*\lambda-3=0 λ22λ3=0,两个特征根分别是 λ 1 = 3 , λ 2 = − 1 \lambda_1=3,\lambda_2=-1 λ1=3,λ2=1

然后第 n 项可以表式为 C 1 ∗ λ 1 n + C 2 ∗ λ 2 n C_1*\lambda_1^n+C_2*\lambda_2^n C1λ1n+C2λ2n

对上面两个分别处理,每一次求的东西是 λ ∑ a i \lambda^{\sum a_i} λai

构造生成函数就是求 ∏ ( λ a i x + 1 ) \prod(\lambda^{a_i}x+1) (λaix+1),分治 f f t fft fft 即可

模数很小,应该不会爆精度

#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 1e5 + 5, Mod = 99991;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b;}
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans, a); return ans; }
cs int inv4 = ksm(4, Mod-2);
int n, k, a[N];
typedef long long ll;
typedef long double ld;
#define poly vector<int>
cs ld PI = acos(-1.0);
struct cp{
	ld x, y;
	cp(ld _x = 0, ld _y = 0){ x = _x, y = _y; }
	cp operator + (cs cp &a){ return cp(x+a.x, y+a.y);}
	cp operator - (cs cp &a){ return cp(x-a.x, y-a.y);}
	cp operator * (cs cp &a){ return cp(x*a.x - y*a.y, x*a.y + y*a.x); }
}A[N << 2], B[N << 2];
poly rev; int up, bit;
void init(int deg){
	bit = 0; up = 1; while(up < deg) up <<= 1, ++bit; rev.resize(up);
	for(int i = 0; i < up; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void FFT(cp *a, int typ){
	for(int i = 0; i < up; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
	for(int i = 1; i < up; i <<= 1){
		cp wn(cos(PI/i), sin(PI/i) * typ);
		for(int j = 0; j < up; j += (i<<1)){
			cp w(1, 0);
			for(int k = 0; k < i; k++, w = w * wn){
				cp x = a[k + j], y = a[k + j + i] * w;
				a[k + j] = x + y; a[k + j + i] = x - y;
			}
		}
	} 
}
poly operator * (poly a, poly b){
	int deg = a.size() + b.size() - 1; init(deg);
	for(int i = 0; i < a.size(); i++) A[i] = cp(a[i], 0);
	for(int i = a.size(); i < up; i++) A[i] = cp(0, 0);
	for(int i = 0; i < b.size(); i++) B[i] = cp(b[i], 0);
	for(int i = b.size(); i < up; i++) B[i] = cp(0, 0);
	FFT(A, 1); FFT(B, 1);
	for(int i = 0; i < up; i++) A[i] = A[i] * B[i];
	FFT(A, -1); a.resize(deg);
	for(int i = 0; i < deg; i++) a[i] = (ll)(A[i].x / up + 0.5) % Mod;
	return a;
}
poly Solve(int l, int r, int lambda){
	if(l == r){ poly f; f.push_back(1); f.push_back(ksm(lambda, a[l] % (Mod-1))); return f; }
	int mid = (l+r) >> 1; return Solve(l, mid, lambda) * Solve(mid+1, r, lambda);  
}
int main(){
	cin >> n >> k;
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	int f0, f1; cin >> f0 >> f1;
	int C0 = mul(add(f0, f1), inv4), C1 = dec(f0, C0);
	cout << add(mul(C1, Solve(1, n, Mod-1)[k]), mul(C0, Solve(1, n, 3)[k]));
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值