ABC256F 题解

前言

题目传送门!

更好的阅读体验?

trick:将 \(D_x\)\(A_x\) 来表示。

思路

首先 \(B_x = \sum\limits_{i=1}^x A_i\)。接着算 \(C_x\),这个并不困难:

\[C_x = \sum\limits_{i=1}^xB_i = \sum\limits_{i=1}^x\sum\limits_{j=1}^i A_j \]

掏一个表格记录它。

\(C_x = \sum\limits_{i=1}^x (x-i+1)A_x\)

类似地,对于 \(D_x\),将式子拆开再组合回来,化简:

\[\begin{aligned} D_x & = \sum\limits_{i=1}^x C_i \\ & = \sum\limits_{i=1}^x \sum\limits_{j=1}^x (x-j+1)A_j \\ & = \sum\limits_{i=1}^x\cdot A_1 + \sum\limits_{i=1}^{x-1} A_2 + \sum\limits_{i=1}^{x-2} A_3 + \cdots + A_x \\ & = \dfrac{x(x+1)}2 \cdot A_1 + \dfrac{(x-1)x}2 \cdot A_2 + \dfrac{(x-2)(x-1)}2 \cdot A_3 + \cdots + A_x \\ & = \sum\limits_{i=1}^x A_i \cdot \dfrac{(x-i+1)(x-i+2)}2 \\ & = \sum\limits_{i=1}^x A_i \cdot \dfrac{x^2 - 2xi + i^2 - 3i + 3x + 2}2 \\ & = \sum\limits_{i=1}^x \dfrac{\color{red}(i^2 - 3i) A_i\color{black} - 2x \cdot \color{red}i\cdot A_i \color{black} + (x^2 + 3x + 2) \cdot \color{red} A_i}2 \end{aligned} \]

标黑的很容易 \(O(1)\) 计算,也就是用数据结构维护红色部分即可(这些部分含有 \(i\) 或者 \(A_i\))。

维护三个数据结构,分别维护 \(\sum (i^2 - 3i) A_i\)\(\sum i\cdot A_i\)\(\sum A_i\)。同时还支持单点更新。

显然用三个树状数组即可拿下。抄一下公式就做完了。

注意 \(\dfrac 12\) 用逆元实现,以及取模比较恶心,推荐在可能溢出的地方都无脑 long long

代码

自认为打得很好看 qwq。

//
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 2e5 + 5, mod = 998244353, inv2 = 499122177; //inv2 即:除以2
int n, q, a[N];
struct BIT { //树状数组板子
	int idx[N];
	int lowbit(int x) {return x & -x;}
	void update(int i, int k) {for (; i <= n; i += lowbit(i)) (idx[i] += k) %= mod;}
	int query(int i) {int ans = 0; for (; i; i -= lowbit(i)) (ans += idx[i]) %= mod; return ans;}
} bit0, bit1, bit2;

typedef long long ll;
void upd0(ll i, ll val) {bit0.update(i, ((i * i - 3 * i + mod) % mod) * val % mod);} //(i^2 - 3i) * Ai
void upd1(ll i, ll val) {bit1.update(i, i * val % mod);} //i * Ai
void upd2(ll i, ll val) {bit2.update(i, val);} //Ai
void upds(ll i, ll val) {upd0(i, val), upd1(i, val), upd2(i, val);}
int main()
{
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]), upds(i, a[i]);
	while (q--)
	{
		int op; ll x, val;
		scanf("%d", &op);
		if (op == 1)
			scanf("%lld%lld", &x, &val),
			upds(x, (-a[x] + val + mod) % mod), a[x] = val; //a[x]=val 就是 a[x]+=(-a[x]+val),还是很显然的吧
		else
			scanf("%lld", &x), //这里直接抄公式即可,注意算完可能变成负数,加一下 mod 来保证答案是正数
			printf("%lld\n", (( 
				+ bit0.query(x)
				- (2 * x) % mod * bit1.query(x) % mod
				+ (x * x + 3 * x + 2) % mod * bit2.query(x) % mod
			) + mod) % mod * inv2 % mod);
	}
	return 0;
}

希望能帮助到大家!

posted @ 2023-05-11 19:30  liangbowen  阅读(46)  评论(0)    收藏  举报