1. 程式人生 > >2018.10.02【校內模擬】聚會(字首和)

2018.10.02【校內模擬】聚會(字首和)

【描述】

在成都的一條街道上, 一共有 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了。。。

其實程式碼裡面就已經有詳細註釋了(不過是英文),為什麼是英文呢,(因為考試的時候懶得切換輸入法)

,其實博主每場考試的程式碼都有英文註釋,不過有的沒ACAC,有的寫得太醜,有的影響閱讀,有的太粗糙,所以都在放上來之前被我刪了。。。 這裡再用中文解釋一遍。

思路:

顯然我們能夠做到O(1)O(1)回答每一個詢問。

我們用distdist陣列表示從1到ii的距離,這樣就可以O(1)O(1)查詢任意兩個家庭之間的距離。 我們用sizsiz陣列表示從1到ii所有家庭的人數和,這樣就可以O(1)O(1)查詢每一段區間的家庭人數總數。

接下來就是本題實現O(1)O(1)回答詢問的關鍵。 我們用prepre陣列表示前11(i1)(i-1)

的所有家庭全部聚集到第ii個家庭的代價。 我們用sufsuf陣列表示後(i+1)(i+1)(n)(n)的所有家庭全部聚集到第ii個家庭的代價。

我們現在考慮當l,rl,r都在xx的前面的時候,移動llrr的所有家庭到xx的代價,記為querypre(l,r,x)querypre(l,r,x)。 都在後面的時候做相似考慮,記為querysuf(l,r,x)querysuf(l,r,x)。 而當xxl,rl,r中間的時候,我們將詢問拆成querypre(l,x1,x)querypre(l,x-1,x)querysuf(x+1,r,x)querysuf(x+1,r,x),採用上面兩種方式考慮。

我僅對queryprequerypre做詳細說明,其餘請讀者自行思考,或者看程式碼裡面的註釋

首先,我們把rr前的所有家庭全部移動到rr,這個代價是pre[r]pre[r]。 然後我們把ll之前的人先暫時送回ll,這個代價是siz[l1](dist[r]dist[l])-siz[l-1]*(dist[r]-dist[l])。 然後現在ll之前的人全部在位置ll,我們將他們全部送回自己的家的代價,就是將他們全部從家中召喚至ll家中代價的相反。這裡代價就是pre[l]-pre[l]。 好了,現在llrr的所有人都在rr家中了。 我們再將他們從rr家中送去xx家,代價就是(siz[r]siz[l1])(dist[x]dist[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;
}