【题解】AT_abc256_f 题解
AT_abc256_f 题解
思路分析
推式子加数据结构题。
先来推 \(C_i\)。
\[\begin{aligned}C_i & = A_1+(A_1+A_2)+(A_1+A_2+A_3)+\ldots+(A_1+A_2+A_3+\ldots+A_i) \\ & =iA_1+(i-1)A_2+\ldots+A_i \\ & = (i-1+1)A_1+(i-2+1)A_2+\ldots+(i-k+1)A_k+\ldots+(i-i+1)A_i \end{aligned}
\]
然后 \(C_i\) 推出来了就去推 \(D_i\)。
这里我们为了方便统计就只考虑 \(A_k\) 的系数:
- 在 \(C_k\) 中,为 \((k-k+1)A_k = 1A_k\)(根据上面推出来的式子)
- 在 \(C_{k+1}\) 中,为 \((k+1-k+1)A_k=2A_k\)。
- 在 \(C_{k+2}\) 中,为 \((k + 2-k+1)A_k = 3A_k\)。
- 在 \(C_{l}\) 中(\(k\le l \le i\)),为 \((l-k+1)A_k\)。
- 在 \(C_{i}\) 中,为 \((i-k+1)A_k\)。
然后发现对于 \(A_k\),它的系数为 \(1+2+3+\ldots+(i-k+1)\),也就是 \(\dfrac{(i-k+2)(i-k+1)}{2}\)。
于是我们有:
\[D_i = \dfrac{(i-1+2)(i-1+1)}{2}A_1 + \dfrac{(i-2+2)(i-2+1)}{2}A_2 + \ldots + \dfrac{(i-k+2)(i-k+1)}{2}A_k +\ldots+ \dfrac{(i-i+2)(i-i+1)}{2}A_i
\]
然后拆开来看看,把 \(A_k\) 乘上去:
\(D_i=\dfrac{(1^2-3\times1)A_1-2i\cdot 1 \cdot A_1+(i^2+3i+2)A_1}{2}+\ldots+\dfrac{(k^2-3k)A_k-2i\cdot k \cdot A_k+(i^2+3i+2)A_k}{2}+\ldots+\dfrac{(i^2-3i)A_i-2i\cdot i \cdot A_i+(i^2+3i+2)A_i}{2}\)
把如下含 \(k\) 的使用树状数组维护之:
-
\((k^2-3k)A_k\)
-
\(k \cdot A_k\)
-
\(A_k\)
无脑更新,无脑查询,无脑取模!
然后做完!
代码
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#define lowbit(x) x&(-x)
#define endl '\n'
#define int long long
using namespace std;
const int N = 3e5 + 10;
const int mod = 998244353;
const int half = 499122177; //二分之一的逆元
template <typename T>
class FkTree //树状数组模板
{
public:
FkTree(int _n = 0)
{
n = _n;
memset(c, 0x0, sizeof(c));
}
T query(int x)
{
T sum = 0;
while(x > 0)
{
sum = _add(sum, c[x]);
x -= lowbit(x);
}
return sum % mod; //一定要取模!我在此处调了1.5h,警钟敲烂
}
void update(int x, T p)
{
while(x <= n)
{
c[x] = _add(c[x], p);
x += lowbit(x);
}
}
private:
T c[N];
T n;
T _add(T a, T b)
{
return (a + b) % mod;
}
};
//三个树状数组
FkTree <int> x(N);
FkTree <int> y(N);
FkTree <int> z(N);
int e[N]; //原数组
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, q;
cin >> n >> q;
for(int i = 1;i <= n;i++)
{
int t;
cin >> t;
e[i] = t;
//三个用树状数组维护的值
x.update(i, ((i % mod * i % mod - 3 * i % mod + mod) % mod) * t % mod);
y.update(i, i % mod * t % mod);
z.update(i, t % mod);
}
for(int i = 1;i <= q;i++)
{
int op;
cin >> op;
if(op == 1)
{
int a, w;
cin >> a >> w;
//无脑更新,注意update是加法
//因此我们就要求一下要加多少
int b = (w - e[a] + mod) % mod;
x.update(a, ((a % mod * a % mod - 3 * a % mod + mod) % mod) * b % mod);
y.update(a, (a % mod * b % mod) % mod);
z.update(a, b % mod);
e[a] = w; //更新原来的
}
else
{
int g;
cin >> g;
//无脑查询,并根据式子计算
cout << half * (((x.query(g) % mod - (((2 * g) % mod) * (y.query(g) % mod)) % mod + mod) % mod + ((g % mod * g % mod + 3 * g % mod + 2) % mod) % mod * z.query(g) % mod) % mod) % mod << endl;
}
}
return 0;
}

浙公网安备 33010602011771号