P5641 【CSGRound2】开拓者的卓识

P5641 【CSGRound2】开拓者的卓识

link

解题思路

我们考虑每个 a i a_i ai s u m k ( 1 , r ) sum_k(1,r) sumk(1,r) 的贡献。

a i a_i ai 有贡献当且仅当
i ∈ [ l k − 1 , r k − 1 ] ⊆ [ l k − 2 , r k − 2 ] ⊆ ⋯ ⊆ [ l 0 , r 0 ] i\in[l_{k-1},r_{k-1}]\subseteq[l_{k-2},r_{k-2}]\subseteq\cdots\subseteq [l_0,r_0] i[lk1,rk1][lk2,rk2][l0,r0]
其中 l 0 = 1 , r 0 = r l_0=1,r_0=r l0=1,r0=r

故有
i ≥ l k − 1 ≥ l k − 2 ≥ ⋯ ≥ l 0 i ≤ r k − 1 ≤ r k − 2 ≤ ⋯ ≤ r 0 i\ge l_{k-1}\ge l_{k-2}\ge\cdots\ge l_0 \\ i\le r_{k-1}\le r_{k-2}\le\cdots\le r_0 ilk1lk2l0irk1rk2r0
考虑第一个条件,设
d k = i − l k − 1 d k − 1 = l k − 1 − l k − 2 ⋯ d 1 = l 1 − l 0 d_k=i-l_{k-1} \\ d_{k-1}=l_{k-1}-l_{k-2} \\ \cdots \\ d_1=l_1-l_0 dk=ilk1dk1=lk1lk2d1=l1l0
则有
d i ≥ 0 ( 1 ≤ i ≤ k ) ∑ i = 1 k d i = i − l 0 = i − 1 d_i\ge 0(1\le i\le k) \\ \sum_{i=1}^kd_i=i-l_0=i-1 di0(1ik)i=1kdi=il0=i1
根据插板法可知,有
( i + k − 2 k − 1 ) \left( \begin{matrix} i+k-2 \\ k-1 \end{matrix} \right) (i+k2k1)
种情况。

同样地,考虑第二个条件,有
( r − i + k − 1 k − 1 ) \left( \begin{matrix} r-i+k-1 \\ k-1 \end{matrix} \right) (ri+k1k1)
种情况。

故最后的答案为
s u m k ( 1 , r ) = ∑ i = 1 r a i ( i + k − 2 k − 1 ) ( r − i + k − 1 k − 1 ) = ∑ i = 0 r − 1 a i + 1 ( i + k − 1 k − 1 ) ( r − i + k − 2 k − 1 ) = ∑ i + j = r − 1 a i + 1 ( i + k − 1 k − 1 ) ( j + k − 1 k − 1 ) sum_k(1,r)=\sum_{i=1}^ra_i \left( \begin{matrix} i+k-2 \\ k-1 \end{matrix} \right) \left( \begin{matrix} r-i+k-1 \\ k-1 \end{matrix} \right) \\ =\sum_{i=0}^{r-1}a_{i+1} \left( \begin{matrix} i+k-1 \\ k-1 \end{matrix} \right) \left( \begin{matrix} r-i+k-2 \\ k-1 \end{matrix} \right) \\ =\sum_{i+j=r-1}a_{i+1} \left( \begin{matrix} i+k-1 \\ k-1 \end{matrix} \right) \left( \begin{matrix} j+k-1 \\ k-1 \end{matrix} \right) sumk(1,r)=i=1rai(i+k2k1)(ri+k1k1)=i=0r1ai+1(i+k1k1)(ri+k2k1)=i+j=r1ai+1(i+k1k1)(j+k1k1)

F ( x ) = ∑ i = 1 n − 1 a i + 1 ( i + k − 1 k − 1 ) x i G ( x ) = ∑ i = 1 n − 1 ( i + k − 1 k − 1 ) x i F(x)=\sum_{i=1}^{n-1}a_{i+1} \left( \begin{matrix} i+k-1 \\ k-1 \end{matrix} \right) x^i \\ G(x)=\sum_{i=1}^{n-1} \left( \begin{matrix} i+k-1 \\ k-1 \end{matrix} \right) x^i \\ F(x)=i=1n1ai+1(i+k1k1)xiG(x)=i=1n1(i+k1k1)xi

s u m k ( 1 , r ) = [ x r − 1 ] F ( x ) G ( x ) sum_k(1,r)=[x^{r-1}]F(x)G(x) sumk(1,r)=[xr1]F(x)G(x)
直接卷积计算即可。

#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, t) memset(f + (s), 0x00, sizeof(int) * ((t) - (s)))
#define cpy(f, g, n) memcpy(g, f, sizeof(int) * (n))
const int MAXN = (1 << 18) + 5, P = 998244353, G = 3, invG = 332748118;
int pls(int a, int b) {return a + b < P ? a + b : a + b - P;}
int mns(int a, int b) {return a < b ? a + P - b : a - b;}
int mul(int a, int b) {return 1ll * a * b % P;}
int qpow(int a, int n) {int ret = 1; for(; n; n >>= 1, a = mul(a, a)) if(n & 1) ret = mul(ret, a); return ret;}
int inv[MAXN], _g[2][MAXN], tr[MAXN], tf;
void init() {
	inv[1] = 1;
	for(int i = 2; i < MAXN; i++) inv[i] = mul(P - P / i, inv[P % i]);
	for(int l = 2; l < MAXN; l <<= 1) {
		_g[1][l] = qpow(G, (P-1) / l);
		_g[0][l] = qpow(invG, (P-1) / l);
	}
}
int getlim(int n) {
	int lim = 1; for(; lim < n + n; lim <<= 1);
	return lim;
}
void tpre(int lim) {
	if(tf == lim) return;
	tf = lim; for(int i = 0; i < lim; i++) tr[i] = (tr[i >> 1] >> 1) | ((i & 1) ? (lim >> 1) : 0);
}
void NTT(int* 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)
		for(int i = 0; i < lim; i += l) 
			for(int j = i, gn = 1; j < i+k; j++, gn = mul(gn, _g[fl][l])) {
				int tt = mul(f[j+k], gn);
				f[j+k] = mns(f[j], tt);
				f[j] = pls(f[j], tt);
			}
	if(!fl)
		for(int i = 0; i < lim; i++) f[i] = mul(f[i], inv[lim]);
}
void Mul(int* f, int* g, int* h, int n) {
	static int 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);
}
int n, k, f[MAXN], g[MAXN], h[MAXN];
int main() {
	init();
	n = read(); k = read();
	g[0] = 1;
	for(int i = 1; i < n; i++) g[i] = mul(g[i-1], mul(i+k-1, inv[i]));
	for(int i = 0; i < n; i++) f[i] = mul(read(), g[i]);
	Mul(f, g, h, n);
	for(int i = 0; i < n; i++) printf("%d ", h[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

日居月诸Rijuyuezhu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值