题解:P12518 「MSTOI-R1」Easy question
PART 1 思路
首先预处理 1 到 20 次幂的前缀和。
具体代码如下:
for(int k=1;k<=20;k++) {p[k][0]=0;for(int i=1;i<=n;i++) {int sum=1;sum=pow(a[i],k);p[k][i]=(p[k][i-1]+sum)%MOD;//k为几次方}}
其中用到了快速幂模板,可见P1226。
然后分三点做题。
1.求l至r之间的值之和
由于数组已经过处理,可直接求和,输出其一次方形式即可,将 p[1][r] 与 p[1][l-1] 相减即为区间和。
int sum=(p[1][r]-p[1][l-1]+MOD)%MOD;
printf("%lld\n",sum);
2.求l至r之间的值的次方之和
和求和同理,只不过将一次方改为 k 次方。
int sum=(p[k][r]-p[k][l-1]+MOD)%MOD;
printf("%lld\n",sum);
3.重头戏!!!
前面两个只是开胃小菜,这才是重点!
但经过预处理,这部分的代码也是异常简短。
int v=(((p[2][r]-p[2][l-1]+MOD)%MOD)-((((((p[1][r]-p[1][l-1]+MOD)%MOD)*((p[1][r]-p[1][l-1]+MOD)%MOD))%MOD)*(pow((r-l+1),MOD-2)))%MOD)+MOD)%MOD;
printf("%lld\n",(v*(r-l+1))%MOD);
PART 2 Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=998244353;
const int N=1e6+10;
int n,q,a[N],p[21][N];
int pow(int b,int a)
{int res=1;b%=MOD;while(a>0) {if(a&1) res=(res*b)%MOD;b=(b*b)%MOD;a>>=1;}return res;
}//快速幂模板
void init()
{for(int k=1;k<=20;k++) {p[k][0]=0;for(int i=1;i<=n;i++) {int sum=1;sum=pow(a[i],k);p[k][i]=(p[k][i-1]+sum)%MOD;}}
}//预处理
signed main() {scanf("%lld%lld",&n,&q);for(int i=1;i<=n;i++) scanf("%lld",&a[i]);init();while(q--) {int op,l,r;scanf("%lld%lld%lld",&op,&l,&r);if(op==1) {int sum=(p[1][r]-p[1][l-1]+MOD)%MOD;printf("%lld\n",sum);} else if(op==2) {int k;scanf("%lld",&k);int sum=(p[k][r]-p[k][l-1]+MOD)%MOD;printf("%lld\n",sum);} else if(op==3) {int v=(((p[2][r]-p[2][l-1]+MOD)%MOD)-((((((p[1][r]-p[1][l-1]+MOD)%MOD)*((p[1][r]-p[1][l-1]+MOD)%MOD))%MOD)*(pow((r-l+1),MOD-2)))%MOD)+MOD)%MOD;printf("%lld\n",(v*(r-l+1))%MOD);}}return 0;
}
总而言之,这整篇题解的核心只有预处理,处理完后就非常简单了