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;
}
总而言之,这整篇题解的核心只有预处理,处理完后就非常简单了