2018.10.02【校内模拟】聚会(前缀和)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82928146

【描述】

在成都的一条街道上, 一共有 N 户人家,每个家庭有 Xi 个人,他们和谐的生活在
一起,作为全国和谐街道,他们经常会小范围组织活动,每次活动会选择一户作为聚点,
并要求某些家庭参加,为了方便通知,村长每次邀请位置连续的家庭。因为每户人数不
同,每个家庭之间有一定距离,村长希望你计算出每次邀请的家庭的移动代价。 第 i 个家
庭移动到家庭 j 的代价是:
Xi*dis(i,j)
dis(i,j)表示 i 到 j 的距离,村长一共安排了 m 次聚会,每次邀请[Li, Ri]的家庭参加

【输入】

第一行两个数表示 n,m
第二行 n-1 个数,第 i 个数表示第 i 个家庭与第 i+1 个家庭的距离 Di
第三行 n 个数,表示每个家庭的人数 Xi
之后 m 行每行三个数 x l r, 表示查询要把区间 [l,r]的家庭移动到 x 点的代价和

【输出】

对于每个询问输出一个数表示答案,对 19260817 取模

【输入样例】

5 5
2 3 4 5
1 2 3 4 5
1 1 5
3 1 5
2 3 3
3 3 3
1 5 5

【输出样例】

5 5
2 3 4 5
1 2 3 4 5
1 1 5
3 1 5
2 3 3
3 3 3
1 5 5

【子任务】

对于 30%的数据, n,m≤1000
对于另外 20%的数据,所有家庭间的距离都为 1
对于另外 20%的数据,所有家庭人数都为 1
对于 100%的数据 , n,m≤200000;Xi, Di <=2*10^9


解析:

一堆同学减法不取模而爆零。我乱写的代码还AC了。。。

其实代码里面就已经有详细注释了(不过是英文),为什么是英文呢,(因为考试的时候懒得切换输入法) ,其实博主每场考试的代码都有英文注释,不过有的没 A C AC ,有的写得太丑,有的影响阅读,有的太粗糙,所以都在放上来之前被我删了。。。
这里再用中文解释一遍。

思路:

显然我们能够做到 O ( 1 ) O(1) 回答每一个询问。

我们用 d i s t dist 数组表示从1到 i i 的距离,这样就可以 O ( 1 ) O(1) 查询任意两个家庭之间的距离。
我们用 s i z siz 数组表示从1到 i i 所有家庭的人数和,这样就可以 O ( 1 ) O(1) 查询每一段区间的家庭人数总数。

接下来就是本题实现 O ( 1 ) O(1) 回答询问的关键。
我们用 p r e pre 数组表示前 1 1 ( i 1 ) (i-1) 的所有家庭全部聚集到第 i i 个家庭的代价。
我们用 s u f suf 数组表示后 ( i + 1 ) (i+1) ( n ) (n) 的所有家庭全部聚集到第 i i 个家庭的代价。

我们现在考虑当 l , r l,r 都在 x x 的前面的时候,移动 l l r r 的所有家庭到 x x 的代价,记为 q u e r y p r e ( l , r , x ) querypre(l,r,x)
都在后面的时候做相似考虑,记为 q u e r y s u f ( l , r , x ) querysuf(l,r,x)
而当 x x l , r l,r 中间的时候,我们将询问拆成 q u e r y p r e ( l , x 1 , x ) querypre(l,x-1,x) q u e r y s u f ( x + 1 , r , x ) querysuf(x+1,r,x) ,采用上面两种方式考虑。

我仅对 q u e r y p r e querypre 做详细说明,其余请读者自行思考,或者看代码里面的注释

首先,我们把 r r 前的所有家庭全部移动到 r r ,这个代价是 p r e [ r ] pre[r]
然后我们把 l l 之前的人先暂时送回 l l ,这个代价是 s i z [ l 1 ] ( d i s t [ r ] d i s t [ l ] ) -siz[l-1]*(dist[r]-dist[l])
然后现在 l l 之前的人全部在位置 l l ,我们将他们全部送回自己的家的代价,就是将他们全部从家中召唤至 l l 家中代价的相反。这里代价就是 p r e [ l ] -pre[l]
好了,现在 l l r r 的所有人都在 r r 家中了。
我们再将他们从 r r 家中送去 x x 家,代价就是 ( s i z [ r ] s i z [ l 1 ] ) ( d i s t [ x ] d i s t [ r ] ) (siz[r]-siz[l-1])*(dist[x]-dist[r])

所以总的代价的式子真的很长,大家看一看代码吧。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
ll getint(){
	re ll num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

inline
void outint(ll a){
	static char ch[23];
	if(a==0)pc('0');
	while(a)ch[++ch[0]]=a-a/10*10,a/=10;
	while(ch[0])pc(ch[ch[0]--]^48);
}

cs ll mod=19260817;
cs int N=200005; 

ll dist[N];//the distance from 1 to i
ll siz[N];//the total num fo people
ll pre[N];//move all 1-(i-1) to i
ll suf[N];//move all (i+1)-n to i
int n;
int m;

inline
ll querypre(int l,int r,int x){//l,r are all at previous poses
	ll res=((pre[r]-pre[l]-siz[l-1]*(dist[r]-dist[l])%mod)+mod)%mod;//first move all to r
	res+=(siz[r]-siz[l-1]+mod)%mod*((dist[x]-dist[r]+mod)%mod)%mod;//then move all to x
	res%=mod;
	res=(res+mod)%mod;
	return res;
}

inline
ll querysuf(int l,int r,int x){//l,r,are all at suffix poses
	ll res=(suf[l]-suf[r]-(siz[n]-siz[r]+mod)%mod*((dist[r]-dist[l])+mod)%mod+mod)%mod; //first move all to l
	res+=(siz[r]-siz[l-1]+mod)%mod*((dist[l]-dist[x]+mod)%mod)%mod; //then move all to x
	res%=mod;
	res=(res+mod)%mod;
	return res;
}

signed main(){
	n=getint();
	m=getint();
	for(int re i=2;i<=n;++i)dist[i]=(dist[i-1]+getint())%mod;
	for(int re i=1;i<=n;++i)siz[i]=(siz[i-1]+getint())%mod;
	
	for(int re i=2;i<=n;++i){
		pre[i]=(pre[i-1]+(dist[i]-dist[i-1])*siz[i-1]%mod)%mod;
	}
	
	for(int re i=n-1;i;--i){
		suf[i]=(suf[i+1]+(siz[n]-siz[i])*(dist[i+1]-dist[i])%mod)%mod;
	}
	
	while(m--){
		int x=getint(),l=getint(),r=getint();
		if(l<x&&x<r){
			outint((querypre(l,x-1,x)+querysuf(x+1,r,x))%mod);pc('\n');
			continue;
		}
		if(x<=l){
			if(l==x)++l; 
			outint(querysuf(l,r,x)),pc('\n');
			continue;
		}
		if(x>=r){
			if(x==r)--r;
			outint(querypre(l,r,x));pc('\n');
			continue;
		}
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/82928146