zoukankan      html  css  js  c++  java
  • [洛谷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;
    }
    
  • 相关阅读:
    Codeforces 468 B Two Sets
    POJ 3080 Blue Jeans
    Scan法求凸包
    线段树 区间更新 区间求和 板子
    拼图设计 课程作业三
    通讯录c#实现 课程作业二
    贷款计算器C#实现 课程作业一
    标准计算器C#实现 课程作业一
    ccf 行车路线
    hdu 4902 Nice boat
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7738634.html
Copyright © 2011-2022 走看看