UOJ450 [集训队作业2018] 复读机 [生成函数+单位根反演]

本文介绍了一种使用单位根反演和多项式卷积解决特定数学问题的算法。通过构造生成函数,分别针对d=2和d=3的情况,详细解释了如何求解第n项的值。对于d=2,采用泰勒展开求解;对于d=3,则通过枚举并计算w(3,0),w(3,1),w(3,2)的出现次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

可以先构造生成函数,然后单位根反演

F(x)=\sum_{i=1}^{inf}[d|i]\frac{x^i}{i!}=\frac{1}{d}\sum_{i=0}^{inf} \frac{x^i}{i!}\sum_{j=0}^{d-1}w_d^{ij}=\frac{1}{d}\sum_{j=0}^{d-1}\sum_{i=0}^{inf}\frac{(x*w_d^j)^i}{i!}=\frac{1}{d}\sum_{j=0}^{d-1}e^{x*w_d^j}

当 d = 2 时   F(x)=\frac{e^x+e^{-x}}{2}, 需要自己与自己卷 k 次,然后求第 n 项

(\frac{e^x+e^{-x}}{2})^k=\frac{\sum_{i=0}^k\binom{k}{i}e^{i*2-k}}{2^k}

泰勒展开一下,第 n 项就是 \frac{\sum_{i=0}^k\binom{k}{i}(i*2-k)^n}{2^k*n!}

当 d = 3时,直接暴力枚举 w(3, 0), w(3, 1), w(3, 2) 出现了多少次

ans=\frac{\sum_{i+j+l=k}\frac{k!}{i!*j!*l!}e^{i*w_3^0+j*w_3^1+l*w_3^2}}{2^k}=\frac{\sum_{i+j+l=k}\frac{k!}{i!*j!*l!}(i*w_3^0+j*w_3^1+l*w_3^2)^n}{2^k}


#include<bits/stdc++.h>
#define N 500050
using namespace std;
typedef long long ll;
const int Mod = 19491001, G = 18827933;
int n, k, d;
ll fac[N], inv[N];
ll mul(ll a, ll b){ return a * b % Mod;}
ll add(ll a, ll b){ return (a + b) % Mod;}
ll power(ll a, ll b){ ll ans = 1;
	a = add(a, Mod);
	for(;b;b>>=1){ if(b&1) ans = mul(ans, a); a = mul(a, a);}
	return ans;
}
ll C(int n, int m){ return mul(mul(fac[n], inv[n-m]), inv[m]);}
int main(){
	scanf("%d%d%d", &n, &k, &d);
	fac[0] = fac[1] = inv[0] = inv[1] = 1;
	for(int i = 2; i <= k; i++) fac[i] = mul(fac[i-1], i);
	inv[k] = power(fac[k], Mod - 2);
	for(int i = k-1; i >= 2; i--) inv[i] = mul(inv[i+1], i+1);
	if(d == 1){ printf("%lld", power(k, n)); return 0;}
	if(d == 2){
		ll ans = 0;
		for(int i = 0; i <= k; i++){
			ans = add(ans, mul(C(k, i), power(2 * i - k, n)));
		} ans = mul(ans, power(power(2, Mod - 2), k));
		cout << ans;
	}
	if(d == 3){
		ll ans = 0; 
		ll w0 = 1, w1 = mul(w0, power(G, (Mod-1) / 3)), w2 = mul(w1, w1);
		for(int i = 0; i <= k; i++){
			for(int j = 0; j <= k; j++){
				if(i + j > k) break;
				int l = k - i - j;
				ll v = mul(mul(fac[k], inv[i]), mul(inv[j], inv[l]));
				ll tmp = add(mul(i, w0), add(mul(j, w1), mul(l, w2)));
				ans = add(ans, mul(v, power(tmp, n)));
			}
		} ans = mul(ans, power(power(3, Mod - 2), k));
		cout << ans; 
	} return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FSYo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值