F - Random Update Query
F - Random Update Query
Problem Statement
You are given an integer sequence of length .
We will perform the following operation on for in this order.
- First, choose an integer between and , inclusive, uniformly at random and denote it as .
- Then, change the value of to the integer .
For the final sequence after the above procedure, print the expected value, modulo , of for each .
How to print expected values modulo
It can be proved that the expected values sought in this problem are always rational. Furthermore, the constraints of this problem guarantee that if each of those expected values is expressed as an irreducible fraction , then is not divisible by .
Now, there is a unique integer between and , inclusive, such that . Report this .
Constraints
- All input values are integers.
Input
The input is given from Standard Input in the following format:
Output
Print the expected values of the final for in the format below, separated by spaces.
Sample Input 1
5 2
3 1 4 1 5
1 2 2
2 4 0
Sample Output 1
499122179 1 665496238 665496236 5
We start from the initial state and perform the following two operations.
- The first operation chooses or uniformly at random, and changes its value to .
- Then, the second operation chooses one of uniformly at random, and changes its value to .
As a result, the expected values of the elements in the final are .
Sample Input 2
2 4
1 2
1 1 3
2 2 4
1 1 5
2 2 6
Sample Output 2
5 6
Sample Input 3
20 20
998769066 273215338 827984962 78974225 994243956 791478211 891861897 680427073 993663022 219733184 570206440 43712322 66791680 164318676 209536492 137458233 289158777 461179891 612373851 330908158
12 18 769877494
9 13 689822685
6 13 180913148
2 16 525285434
2 14 98115570
14 17 622616620
8 12 476462455
13 17 872412050
14 15 564176146
7 13 143650548
2 5 180435257
4 10 82903366
1 2 643996562
8 10 262860196
10 14 624081934
11 13 581257775
9 19 381806138
3 12 427930466
6 19 18249485
14 19 682428942
Sample Output 3
821382814 987210378 819486592 142238362 447960587 678128197 687469071 405316549 318941070 457450677 426617745 712263899 939619994 228431878 307695685 196179692 241456697 12668393 685902422 330908158
解题思路
令 表示第 个数的期望值,在没有执行任何操作前显然都有 。对于某个询问 如果 ,记 ,那么第 个数有 的概率变成 ,有 的概率还是其本身即 ,因此第 个数的期望就变成了 。
显然对于每个询问我们不可能一个个数去修改,这样做的时间复杂度为 。可以发现在每个询问中我们都需要对区间 中的每个 先乘上一个数 ,再加上一个数 ,因此容易想到用线段树去维护。
线段树的节点维护两个懒标记, 表示这个区间累加的值, 表示这个区间累乘的值。在一次操作中假设要对某个区间的数先乘上 再加上 ,考虑懒标记如何更新。不妨假设当前的懒标记最后作用在 上,那么 就会被更新成 ,再更新就会得到 ,即对应的懒标记的更新就是 。
在执行完所有的操作后只需单点查询,那么第 个数的期望就是 。可以发现线段树只有下传懒标记的操作,而没有向上更新的操作。
另外这题还有对应的扩展,参考题目 [AHOI2009] 维护序列,需要查询区间和,每次的修改操作是对某个区间加上或乘上某个数。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, mod = 998244353;
int a[N];
struct Node {
int l, r, s, p;
}tr[N * 4];
void build(int u, int l, int r) {
tr[u] = {l, r, 0, 1};
if (l == r) {
tr[u].p = a[l] % mod;
}
else {
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
}
}
void pushdown(int u) {
if (tr[u].s || tr[u].p != 1) {
tr[u << 1].s = (1ll * tr[u << 1].s * tr[u].p + tr[u].s) % mod;
tr[u << 1].p = 1ll * tr[u << 1].p * tr[u].p % mod;
tr[u << 1 | 1].s = (1ll * tr[u << 1 | 1].s * tr[u].p + tr[u].s) % mod;
tr[u << 1 | 1].p = 1ll * tr[u << 1 | 1].p * tr[u].p % mod;
tr[u].s = 0;
tr[u].p = 1;
}
}
void modify(int u, int l, int r, int s, int p) {
if (tr[u].l >= l && tr[u].r <= r) {
tr[u].s = (1ll * tr[u].s * p + s) % mod;
tr[u].p = 1ll * tr[u].p * p % mod;
}
else {
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) modify(u << 1, l, r, s, p);
if (r >= mid + 1) modify(u << 1 | 1, l, r, s, p);
}
}
int query(int u, int x) {
if (tr[u].l == tr[u].r) return (tr[u].s + tr[u].p) % mod;
pushdown(u);
if (x <= tr[u].l + tr[u].r >> 1) return query(u << 1, x);
return query(u << 1 | 1, x);
}
int qmi(int a, int k) {
int ret = 1;
while (k) {
if (k & 1) ret = 1ll * ret * a % mod;
a = 1ll * a * a % mod;
k >>= 1;
}
return ret;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
}
build(1, 1, n);
while (m--) {
int l, r, x;
scanf("%d %d %d", &l, &r, &x);
int t = r - l + 1, p = qmi(t, mod - 2);
modify(1, l, r, 1ll * x * p % mod, (t - 1ll) * p % mod);
}
for (int i = 1; i <= n; i++) {
printf("%d ", query(1, i));
}
return 0;
}
参考资料
Editorial - AtCoder Beginner Contest 332:https://atcoder.jp/contests/abc332/editorial/7926
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17896596.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效