[ARC111F] Do you like query problems?
题意:
给出三个数 。
你有一个长度为 的序列 ,初始全为为 ,你有三种操作:
操作 :给出 ,让区间 对 取 。
操作 :给出 ,让区间 对 取 。
操作 ,给出 ,求区间和,将其累加进一个叫 的变量里。
你并不需要维护这个数据结构,而是统计一共有 个操作的情况下,所有不同的操作序列中 操作得到的 的总和,对 取模。你需要保证 。
分析:
显然的,输入的数据最多只可能有 种。
对于这种问题,可以通过计算期望使得计算更简便。
不妨考虑计算每个位置对答案的贡献。
记一个 表示经过 次修改操作最后变成 的概率。
考虑 dp 计算,如果要修改 ,能改变 的只会是 以及 。
易得:
然后再记一个 表示一个数经过 次修改得期望值。
但不可能每次操作 都包含这个数吧(滑稽
因此需要记一个 表示 被包含得概率。显然 。
于是我们就把 升级到 表示 经过 次全局操作得期望值:
令 。
表示操作到 头上得次数,最后一步用了二项式定理推导。
再加入一波修改操作 表示 经过 次操作(包含查询)的期望值:
那么最后 的期望值为
显然可以用等比数列求和快速计算。
最后答案就是
完结撒花!
代码:
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
int Pow(int a, int n) {
if(n == 0) return 1;
if(n == 1) return a % mod;
int x = Pow(a, n / 2);
if(n % 2 == 0) return x * x % mod;
else return x * x % mod * a % mod;
}
int read() {
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
void write(int x) {
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar('0' + x % 10);
}
int inv(int x) {
return Pow(x, mod - 2);
}
int n, m, q, ans;
signed main() {
cin >> n >> m >> q;
for(int i = 1; i <= n; i++) {
int p = i * (n - i + 1) % mod * inv((n + 1) * n / 2 % mod) % mod;
int P = (1 - p * inv(2) % mod + mod) % mod;
int z = (2 * m % mod * P % mod + 1) % mod * inv(2 * m + 1) % mod;
int S = (Pow(z, q) - 1 + mod) % mod * inv(z - 1) % mod;
ans = (ans + p * inv(2 * m + 1) % mod * (m - 1) % mod * inv(2) % mod * ((q - S + mod) % mod) % mod) % mod;
}
cout << ans * Pow((2 * m + 1) % mod * n % mod * (n + 1) % mod * inv(2) % mod, q) % mod;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】