【题解】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;
}
posted @ 2023-10-04 15:04  邻补角-SSA  阅读(34)  评论(0)    收藏  举报  来源