洛谷 P12518 「MSTOI-R1」Easy question 题解
传送门:P12518 「MSTOI-R1」Easy question
写在之前
(机房大佬:我第一眼以为有修改操作,就想到建20棵树。)实际上不用建20棵树,学算法学多了导致的。
题意大意
给一个序列 \(a\),长度为 \(n\),你需要进行下面三种操作:
-
1 l r表示求 \(\sum\limits_{i=l}^{r}a_i\)。 -
2 l r k表示求 \(\sum\limits_{i=l}^{r}{a_i}^k\)。 -
3 l r表示求 \((r-l+1)\cdot \sum\limits_{i=l}^r\left(a_i-\overline a\right)^2\),其中 \(\overline a\) 为序列中 \([l,r]\) 的平均数。
思路分析
操作1
发现就是求序列区间 \([l,r]\) 的和,于是很容易想到前缀和做法,前缀和用数组 \(sum\) 存储。
操作2
求序列区间 \([l,r]\) 中每个数的 \(k\) 次方的和。一通计算下来发现没有时间复杂度合理的简便计算。然后想到在输入原序列时对每个数的 \(k\) 次方进行预处理,同样可以进行前缀和操作,于是将前缀和数组开成二维数组,其中 \(sum_{i,j}\) 表示序列前 \(i\) 个数的 \(j\) 次方的和。
操作3
一个形似求方差的操作,我们可以将这个式子先写出来:设 \(ans = (r-l+1)\cdot \sum\limits_{i=l}^r\left(a_i-\overline a\right)^2\)。
则可以推出如下式子。
\(\begin{aligned} ans &= (r - l + 1) \cdot [(a_l - \overline a)^2 + (a_{l+1} - \overline a)^2 + \cdots + (a_r -\overline a)^2] \\ &= (r - l + 1) \cdot [(a_l^2 - 2a_l\overline a + {\overline a}^2) + (a_{l+1}^2 - 2a_{l+1}\overline a + {\overline a}^2) + \cdots + (a_r^2 - 2a_r\overline a + \overline a^2)] \\ &=(r - l + 1) \cdot [\sum\limits_{i=l}^{r}{a_i}^2 - 2\overline a \cdot \sum\limits_{i=l}^{r}{a_i} + (r - l + 1) \cdot \overline a^2] \end{aligned}\)
而根据 \(\overline a = \frac{\sum\limits_{i=l}^{r}{a_i}}{r-l+1}\),将 \((r - l + 1)\) 乘入括号,得到式子:\(ans = (r - l + 1)\cdot \sum\limits_{i=l}^{r}{a_i} ^2 - 2(\sum\limits_{i=l}^{r}{a_i})^2 + (\sum\limits_{i=l}^{r}{a_i})^2\)。
最后化简可得\(ans = (r - l + 1)\cdot \sum\limits_{i=l}^{r}{a_i} ^2 - (\sum\limits_{i=l}^{r}{a_i})^2\)。
化简后可知答案一定是一个整数。
而我们已经用了前缀和数组存储了序列前 \(i\) 个数的 \(2\) 次方的和,因此操作3的时间复杂度为 \(O(1)\)。
代码
long long n, q;
unsigned long long opt, l, r, k, ans, a;
unsigned long long sum_1, sum_2;
unsigned long long mod = 998244353;
unsigned long long num[1000010];//原数组
unsigned long long sum[1000010][21];//前缀和数组,sum[i][j] 表示序列前i个数的j次方的和
int main(){
ios::sync_with_stdio(false);//解绑操作,加快数据输入输出速度
cin.tie(0);
cout.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; i++){
cin >> num[i];
a = num[i];
for(int j = 1; j <= 20; j++){//前缀和数组预处理
sum[i][j] =(sum[i - 1][j] + a + mod) % mod;
a = a * num[i] % mod;
}
}
for(int i = 1; i <= q; i++){
cin >> opt;
if(opt == 1){//操作1
cin >> l >> r;
ans = sum[r][1] - sum[l - 1][1];
} else if(opt == 2){//操作2
cin >> l >> r >> k;
ans = sum[r][k] - sum[l - 1][k];
}else{//操作3
cin >> l >> r;
sum_1 = sum[r][1] - sum[l - 1][1];//区间和
sum_2 = sum[r][2] - sum[l - 1][2];//区间平方和
ans = ((sum_2 + mod) % mod * (r - l + 1 + mod) % mod - (sum_1 * sum_1) % mod + mod) % mod;
}
ans += mod;
cout << ans % mod << '\n';
}
return 0;
}
写在最后
赛时被模数嗯控,最后40分遗憾离场,本蒟蒻要重修语法了(悲)。
帮到你的话请点赞题解喵,点赞题解谢谢喵
本文来自 er_mao_jpg ,转载请注明原文链接:https://www.cnblogs.com/er-mao-jpg233/p/18996589, 欢迎各路大佬参观投喂~

浙公网安备 33010602011771号