1. 程式人生 > >2018年9月23日提高組

2018年9月23日提高組

A 農夫約的假期

在某國有一個叫農夫約的人,他養了很多羊,其中有兩頭名叫mm和hh,他們的歌聲十分好聽,被當地人稱為“魔音”······
農夫約也有自己的假期呀!他要去海邊度假,然而mm和hh不能離開他。沒辦法,他只好把他們兩個帶上。
到了海邊,農夫約把他的羊放在一個(nn)的矩陣(有nn個方格)裡。mm和hh十分好動,他們要走到m(m<=n*n)個地方,第i個地方的座標為(x[i](行),y[i](列)),每到一個地方他們會高歌一曲,製造q[i]點魔音值,因為他們的魔音十分獨特,他們的聲音只能橫著或豎著傳播。每傳播一格,魔音值會增加1。(傳播的格子數取最小的)接下來農夫約要住酒店。為了方便照顧小羊們,他選的酒店的座標要在矩陣內。但小羊們的魔音讓他十分頭疼。他想求出魔音值最小的地方。
他還要享受他的假期,所以他把這個任務交給你了,加油(_

)。

  求中位數即可
#include <cstdio>
#include <algorithm>

using namespace std;

int n,m,z;
int x[100005],y[100005],q[100005];

int main(){
	scanf("%d%d%d",&n,&m,&z);
	for (int i=1;i<=m;i++)
		scanf("%d%d%d",&x[i],&y[i],&q[i]);
		
	sort(x+1,x+1+m);
	sort(y+1,y+1+m);
	int cx,cy;
	long long ans=0;
	cx=x[m/2];cy=y[m/2];
	if (m%2==1){
			cx=x[m/2+1];cy=y[m/2+1];
	}	
	for (int i=1;i<=m;i++)
		ans+=abs(x[i]-cx)*z+abs(y[i]-cy)*z+q[i];
	printf("%lld\n",ans);
	printf("%d %d",cx,cy);
}

B 小x遊世界樹

小x得到了一個(不可靠的)小道訊息,傳說中的神島阿瓦隆在格陵蘭海的某處,據說那裡埋藏著亞瑟王的寶藏,這引起了小x的好奇,但當他想前往阿瓦隆時發現那裡只有聖誕節時才能到達,然而現在已經春天了,不甘心的他將自己的目的地改成了世界樹,他耗費了大量的時間,終於將自己傳送到了世界樹下。世界樹是一棵非常巨大的樹,它有著許許多多的枝條以及節點,每個節點上都有一個平臺。好不容易來到傳說中的世界樹下,小x當然要爬上去看看風景。小x每經過一條邊都會耗費體力值。然而世界樹之主想給他弄(gáo)些(dǐan)麻(shì)煩(qíng),於是他在每條邊上都設了一個魔法陣,當小x踏上那條邊時會被傳送回根節點,魔法陣只生效一次。這豈不是要累死小x?幸運的是,每個平臺上都有無數個加速器,這些加速器可以讓小x在當前節點所連的邊上耗費的體力值減少,不同平臺的加速器效能不一定相同,但同一個平臺的加速器效能絕對相同。世界樹之主給了小x一次“換根”的機會,他可以將世界樹的任何一個節點變為根,但所有的邊都不能改變。小x想問你,將根換為哪個節點能使小x爬到世界樹上的每個節點耗費的體力值和最少。預設編號為1的點為初始根。

下面是一個修改中未完成的程式

#include <cstdio>
#include <cstring>

using namespace std;

int n,ans,st,cnt;
int a[700005];
int ls[700005],ne[700005],to[700005],d[700005];
int b[700005],f[700005],son[700005];

void dfs(int k){
	b[k]=1;
	int u=ls[k],bz=0,bbz=0;
	while (u){
		if (!b[to[u]]){
			int ccd=(son[k]-son[to[u]])*d[u^1]-son[to[u]]*d[u];
			f[to[u]]+=ccd+f[k];
			if (f[to[u]]<ans){ans=f[to[u]];st=to[u];}
			dfs(to[u]);
			
		}
		u=ne[u];
	}
}

void dfs1(int k){
	b[k]=1;
	son[k]=1;
	int u=ls[k];
	int sss=f[k];
	while (u){
		if (!b[to[u]]){
			f[to[u]]=f[k]+d[u];			
			dfs1(to[u]);
			son[k]+=son[to[u]];
			sss+=f[to[u]];
		}
		u=ne[u];
	}
	f[k]=sss;
}

int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	cnt=1;
	for (int i=1;i<n;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		ne[++cnt]=ls[x];ls[x]=cnt;to[cnt]=y;d[cnt]=z-a[x];
		ne[++cnt]=ls[y];ls[y]=cnt;to[cnt]=x;d[cnt]=z-a[y];
	}
	memset(b,0,sizeof(b));
	memset(f,0,sizeof(f));
	dfs1(1);
	ans=f[1];st=1;
	
	memset(b,0,sizeof(b));
	dfs(1);
		
	printf("%d\n",st);
	printf("%d",ans);
}

C 觀察

出題人給出一顆以1為根的樹,一開始每個節點都是一顆棋子,一面白一面黑,白色的面朝上
接下來就q次操作,操作分兩種
0操作 將一個顆棋子翻轉
1操作 詢問一顆棋子與所有面朝上為黑色的棋子lca最深的那個的編號
在這裡插入圖片描述