[洛谷P3932]浮游大陆的68号岛

题目大意:有一行物品,每两个物品之间有一个距离。每个物品有一个价值。现在问你若干问题,每个问题问你把l~r所有物品全部搬到物品x处需要多少价值。

把物品a搬到物品b处的价值为物品a的价值乘a到b的距离。

解题思路:前缀和。

首先我们考虑$x<l<r$的情况。

发现答案为$sumlimits ^{r}_{i=l} a[i]×dis(x,i)$。其中a[i]是第i个物品的价值,dis(x,i)表示x到i的距离。

首先我们容易想到用前缀和保存距离,即$dis[i]=sumlimits^r _{i=2}p[i]$。p[i]表示i到i-1的距离。

但时间复杂度仍然很高,怎么办?

我们可以再用一个前缀和,用ds[i]保存第1到i个物品,每个物品到第一个物品的价值总和,即$ds[i]=sumlimits^r_i=1 a[i]×dis[i]$。

那么ds[r]-ds[l-1]就表示l到r所有物品搬到1的价值,可是要求的是到x的距离,怎么办?

我们发现,这个答案多出来的其实是l到r所有物品搬dis[x]距离的价值,即多搬了1到x的距离。

那么就在答案中减去$sumlimits^r _{i=l} a[i]×dis[x]=(sumlimits^r_{i=l}a[i])×dis[x]$。

发现a[i]也可以用前缀和,那么我们令$sum[i]=sumlimits^r _{i=1} a[i]$。

那么最后答案为$ds[r]-sd[l-1]+dis[x]×(sum[r]-sum[l-1])$。

当$l<r<x$时,可以用后缀和,然后求解即可。

当$lleq xleq r$时,我们把它分成两段,l~x-1和x+1~r,分别求解即可。

由于求解时间复杂度$O(1)$,求前缀和时间复杂度$O(n)$,所以总时间复杂度$O(n+m)$,在洛谷神机+O2下时间完全不是问题。

注意边算边模和long long(数组也要,不然答案就会莫名其妙地错误)。

C++ Code:

#include<cstdio>
#include<cctype>
using namespace std;
#define mod 19260817
#define N 200020
int n,m,a[N];
long long disl[N],disr[N],dsl[N],dsr[N],suml[N],sumr[N];
inline int readint(){
	char c=getchar();
	for(;!isdigit(c);c=getchar());
	int d=0;
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^'0');
	return d;
}
inline long long ansL(int l,int r,int x){return((dsl[r]-dsl[l-1]+mod)%mod-(long long)disl[x]*((suml[r]-suml[l-1]+mod)%mod)%mod+mod)%mod;}
inline long long ansR(int l,int r,int x){return((dsr[l]-dsr[r+1]+mod)%mod-(long long)disr[x]*((sumr[l]-sumr[r+1]+mod)%mod)%mod+mod)%mod;}
int main(){
	n=readint();
	m=readint();
	disl[1]=disr[n]=suml[0]=sumr[n+1]=0;
	for(int i=2;i<=n;++i)disl[i]=(disl[i-1]+(a[i]=readint()%mod))%mod;
	for(int i=n;i>1;--i)disr[i-1]=(disr[i]+a[i])%mod;
	for(int i=1;i<=n;++i)suml[i]=(suml[i-1]+(a[i]=readint()%mod))%mod;
	for(int i=n+1;i;--i)sumr[i]=(sumr[i+1]+a[i])%mod;
	dsl[0]=dsr[n+1]=0;
	for(int i=1;i<=n;++i)
	dsl[i]=(dsl[i-1]+disl[i]*a[i]%mod)%mod;
	for(int i=n;i;--i)
	dsr[i]=(dsr[i+1]+disr[i]*a[i]%mod)%mod;
	while(m--){
		int x=readint(),l=readint(),r=readint();
		if(l>r)l^=r^=l^=r;
		if(x<l)printf("%d
",(int)ansL(l,r,x));else
		if(x>r)printf("%d
",(int)ansR(l,r,x));else
		printf("%d
",(int)((ansR(l,x-1,x)+ansL(x+1,r,x))%mod));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7738634.html