P5488 差分与前缀和 解题报告

P5488 差分与前缀和 解题报告

link

题目大意

给定一个长度为 n n n 的序列 a i a_i ai ,求其 k k k 阶差分或前缀和。对 1004535809 取模。

1 ≤ n ≤ 1 0 5 1\le n \le 10^5 1n105 0 ≤ a i ≤ 1 0 9 0\le a_i\le 10^9 0ai109 1 ≤ k ≤ 1 0 2333 , k ≢ 0 ( m o d 1004545809 ) 1\le k\le 10^{2333},k\not\equiv 0\pmod {1004545809} 1k102333,k0(mod1004545809)

解题思路

一道生成函数裸题。

设序列的OGF为 A ( x ) = ∑ n ≥ 0 a n x n A(x)=\sum\limits_{n\ge 0}a_nx^n A(x)=n0anxn

则求差分为 A − ( x ) = ( 1 − x ) A ( x ) A^{-}(x)=(1-x)A(x) A(x)=(1x)A(x) k k k 阶差分是 A k − = ( 1 − x ) k A ( x ) A^{k-}=(1-x)^kA(x) Ak=(1x)kA(x)

这是因为
A − ( x ) = [ x 0 ] A ( x ) + ∑ n ≥ 1 ( a n − a n − 1 ) x n = [ x 0 ] A ( x ) + ∑ n ≥ 1 a n x n − ∑ n ≥ 1 a n − 1 x n = A ( x ) − x ∑ n ≥ 1 a n − 1 x n − 1 = A ( x ) − x A ( x ) = ( 1 − x ) A ( x ) A^-(x)=[x^0]A(x)+\sum_{n\ge 1}(a_n-a_{n-1})x^n\\ =[x^0]A(x)+\sum_{n\ge 1}a_nx^n-\sum_{n\ge 1}a_{n-1}x^n\\ =A(x)-x\sum_{n\ge 1}a_{n-1}x^{n-1}\\ =A(x)-xA(x)=(1-x)A(x) A(x)=[x0]A(x)+n1(anan1)xn=[x0]A(x)+n1anxnn1an1xn=A(x)xn1an1xn1=A(x)xA(x)=(1x)A(x)
而求前缀和为 A + ( x ) = 1 1 − x A ( x ) A^+(x)=\dfrac1{1-x}A(x) A+(x)=1x1A(x) k k k 阶前缀和为 A k + = 1 ( 1 − x ) k A ( x ) A^{k+}=\dfrac 1 {(1-x)^k}A(x) Ak+=(1x)k1A(x)

这是因为
A + ( x ) = ∑ n ≥ 0 ∑ i = 0 n a i ⋅ x n = ∑ i ≥ 0 a i ∑ n ≥ i x n = ∑ i ≥ 0 a i x i 1 − x = 1 1 − x ∑ i ≥ 0 a i x i = 1 1 − x A ( x ) A^+(x)=\sum_{n\ge 0}\sum_{i=0}^na_i\cdot x^n\\ =\sum_{i\ge 0}a_i\sum_{n\ge i}x^n\\ =\sum_{i\ge 0}a_i\dfrac{x^i}{1-x}\\ =\dfrac 1 {1-x}\sum_{i\ge 0}a_ix^i=\dfrac 1 {1-x}A(x) A+(x)=n0i=0naixn=i0ainixn=i0ai1xxi=1x1i0aixi=1x1A(x)
所以只要求 ( 1 − x ) α (1-x)^{\alpha} (1x)α ,再乘起来即可。那么直接用个 Ln 和 Exp 即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
char In[1 << 20], *ss = In, *tt = In;
#define getchar() (ss == tt && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
ll read() {
	ll x = 0, f = 1; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + int(ch - '0');
	return x * f;
}
#define clr(f, s, e) memset(f + (s), 0x00, sizeof(ll) * ((e) - (s)))
#define cpy(f, g, len) memcpy(g, f, sizeof(ll) * (len))
const int MAXN = 1 << 18, P = 1004535809, G = 3, invG = 334845270;
ll pls(ll a, ll b) {return a + b < P ? a + b : a + b - P;}
ll mns(ll a, ll b) {return a < b ? a + P - b : a - b;}
ll mul(ll a, ll b) {return a * b % P;}
ll qpow(ll a, int n) {ll ret = 1; for(; n; n >>= 1, a = mul(a, a)) if(n & 1) ret = mul(ret, a);  return ret;}
int tr[MAXN], tf;
int getlim(int n) {
	int lim = 1; for(; lim < n + n; lim <<= 1);
	return lim;
}
void tpre(int lim) {
	if(lim == tf) return ;
	tf = lim; for(int i = 0; i < lim; i++) tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? (lim >> 1) : 0);
}
void NTT(ll* f, int lim, int fl) {
	tpre(lim); for(int i = 0; i < lim; i++) if(i < tr[i]) swap(f[i], f[tr[i]]);
	for(int l = 2, k = 1; l <= lim; l <<= 1, k <<= 1) {
		ll g0 = qpow(fl ? G : invG, (P-1) / l);
		for(int i = 0; i < lim; i += l) {
			ll gn = 1;
			for(int j = i; j < i+k; j++, gn = mul(gn, g0)) {
				ll tt = mul(gn, f[j+k]);
				f[j+k] = mns(f[j], tt);
				f[j] = pls(f[j], tt);
			}
		}
	}
	if(!fl) {
		ll in = qpow(lim, P-2);
		for(int i = 0; i < lim; i++) f[i] = mul(f[i], in);
	}
}
void Mul(ll* f, ll* g, ll* h, int n) {
	static ll a[MAXN], b[MAXN];
	int lim = getlim(n);
	cpy(f, a, n); clr(a, n, lim);
	cpy(g, b, n); clr(b, n, lim);
	NTT(a, lim, 1); NTT(b, lim, 1);
	for(int i = 0; i < lim; i++) h[i] = mul(a[i], b[i]);
	NTT(h, lim, 0); clr(h, n, lim);
}
void Inv(ll* f, ll* g, int n) {
	static ll a[MAXN];
	if(n == 1) {g[0] = qpow(f[0], P-2); return ;}
	Inv(f, g, (n + 1) >> 1);
	int lim = getlim(n);
	clr(g, (n + 1) >> 1, lim);
	cpy(f, a, n); clr(a, n, lim);
	NTT(a, lim, 1); NTT(g, lim, 1);
	for(int i = 0; i < lim; i++) g[i] = (2 - a[i] * g[i] % P + P) * g[i] % P;
	NTT(g, lim, 0); clr(g, n, lim);
}
void Deriv(ll* f, ll* g, int n) {
	for(int i = 1; i < n; i++) g[i-1] = mul(f[i], i);
	g[n-1] = 0;
}
void Integ(ll* f, ll* g, int n) {
	for(int i = 1; i < n; i++) g[i] = mul(f[i-1], qpow(i, P-2));
	g[0] = 0;
}
void Ln(ll* f, ll* g, int n) {
	static ll a[MAXN], b[MAXN];
	Deriv(f, a, n); Inv(f, b, n);
	Mul(a, b, a, n); Integ(a, g, n);
}
void Exp(ll* f, ll* g, int n) {
	static ll a[MAXN], b[MAXN];
	if(n == 1) {g[0] = 1; return;}
	Exp(f, g, (n + 1) >> 1);
	int lim = getlim(n);
	clr(g, (n + 1) >> 1, lim);
	cpy(f, a, n); clr(a, n, lim);
	Ln(g, b, n); clr(b, n, lim);
	NTT(a, lim, 1); NTT(b, lim, 1); NTT(g, lim, 1);
	for(int i = 0; i < lim; i++) g[i] = (1 - b[i] + a[i] + P) * g[i] % P;
	NTT(g, lim, 0); clr(g, n, lim);
}
ll readk() {
	ll x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar());
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x * 10 + ch - '0') % P;
	return x;
}
int n;
ll k, t, a[MAXN], b[MAXN], c[MAXN];
int main() {
	n = read(); k = readk(); t = read();
	k = (t == 0 ? P-k : k);
	for(int i = 0; i < n; i++) a[i] = read();
	b[0] = 1; b[1] = P-1;
	Ln(b, c, n);
	for(int i = 0; i < n; i++) c[i] = mul(c[i], k);
	Exp(c, b, n);
	Mul(a, b, a, n);
	for(int i = 0; i < n; i++) printf("%lld ", a[i]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

日居月诸Rijuyuezhu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值