P15966 合成西瓜 题解

活动公告91942026-09-02 02:24:38

P15966 合成西瓜 题解

Snowflake_Fairy

·

2026-03-28 21:50:32

·

题解

前言

蒟蒻一枚,做了两小时,才第 91 名,后面两道题甚至还没来得及看。

纪念 2026 年 3 月 28 日 Atcoder 第一次单场 perf 大于 2000。

解题思路

有点意思。看完题目后居然茫然了一阵。

定义 f(n) 为目标西瓜等级为 n 时的答案。

当 x \leq y 时,可以直接生成一个等级为 x 的西瓜,所以对于 0 \leq i \leq y, f(i) = 1。

当 x > y 时,我们先找到初始序列,再根据之后的情况往里面添加。根据贪心策略,肯定希望每一次都可以产生更高等级的西瓜。

所以初始时构造序列为 [0,1,2,\cdots, y],再选择区间 [0, y + 1],这样就有了等级为 y + 1 的西瓜,所以 f(y + 1) = y + 1,当然等价于因为需要等级小于 y + 1 的西瓜各一个,所以将所有等级小于 y + 1 的西瓜产生的代价都加起来,即 f(y + 1) = f(0) + f(1) + \cdots + f(y)。于是我们就可以推广为 i > y, f(i) = \displaystyle\sum_{k = 0} ^ {i - 1} f(k)。

然后发现这样递推是 \mathcal{O}(n^2) 的,所以可以使用一个变量 s,每一次 s 都增加 f(k),再用一个答案变量每次累加 s,这样就优化成了 \mathcal{O}(n) 的了,于是你有了 70pts。

似乎没辙了,于是去刷了两个 U 放松一下,回来瞬间精神倍增,反正没事,就开始迭代。 \because f(y + 1) = y + 1$$ 且 $$f(y + 2) = \displaystyle\sum_{k = 0} ^ {y + 1} f(k)

\therefore f(y + 2) = f(y + 1) + y + 1 = 2f(y + 1) = 2(y + 1)

\therefore f(y + 3) = f(y + 2) + f(y + 1) + y + 1 = 2f(y + 2) = 4f(y + 1) = 4(y + 1)

\cdots

因此得到 f(y + p) = 2^{p - 1}(y + 1),写一个快速幂就好了。

所以在遇到没有思路的时候可以适当放松一下,回来说不定就有了新的灵感。

备注:感谢 @SubtleFlicker 找到题解中的逻辑错误,现已更正。

CODE:

#include

using namespace std;

#define int long long

const int mod = 998244353;

inline int qmi(int a, int b) {

int res = 1;

while (b) {

if (b & 1) {

res = res * a % mod;

}

a = a * a % mod;

b >>= 1;

}

return res;

}

signed main() {

ios::sync_with_stdio(false);

ios_base::sync_with_stdio(false);

cin.tie(0), cout.tie(0);

//f(n) = y + 1, f(n + 1) = f(n) + n = 2n, f(n + 2) = f(n + 1) + f(n) + n = 2n + n + n = 4n, f(n + 3) = f(n + 2) + f(n + 1) + f(n) + n = 4n +2n + 2n = 8n

int T;

cin >> T;

while (T--) {

int x, y;

cin >> x >> y;

if (x <= y) {

cout << "1\n";

} else {

cout << qmi(2, x - y - 1) * (y + 1) % mod << "\n";

}

}

return 0;

}

德转统计本届世界杯参赛球员联赛分布:英超162人,德甲100人
OpenShot 视频编辑器