2014-04-19編程之美初賽題目及答案解析

第一題:

描述

一般來說,我們採用針孔相機模型,也就是認爲它用到的是小孔成像原理。

在相機座標系下,一般來說,我們用到的單位長度,不是“米”這樣的國際單位,而是相鄰像素的長度。而焦距在相機座標系中的大小,是在圖像處理領域的一個非常重要的物理量。

假設我們已經根據相機參數,得到鏡頭的物理焦距大小(focal length),和相機膠片的寬度(CCD width),以及照片的橫向分辨率(image width),則具體計算公式爲:

Focal length in pixels = (image width in pixels) * (focal length on earth) / (CCD width on earth)

比如說對於Canon PowerShot S100, 帶入公式得

Focal length in pixels = 1600 pixels * 5.4mm / 5.27mm = 1639.49 pixels

現在,請您寫一段通用的程序,來求解焦距在相機座標系中的大小。


輸入

多組測試數據。首先是一個正整數T,表示測試數據的組數。

每組測試數據佔一行,分別爲

鏡頭的物理焦距大小(focal length on earth)

相機膠片的寬度(CCD width on earth)

照片的橫向分辨率大小(image width in pixels),單位爲px。

之間用一個空格分隔。


輸出

每組數據輸出一行,格式爲“Case X: Ypx”。 X爲測試數據的編號,從1開始;Y爲焦距在相機座標系中的大小(focallength in pixels),保留小數點後2位有效數字,四捨五入取整。


數據範圍

對於小數據:focal length on earth和CCD width on earth單位都是毫米(mm)

對於大數據:長度單位還可能爲米(m), 分米(dm), 釐米(cm), 毫米(mm), 微米(um),納米(nm)

解析:

感覺這個題目可能需要用java的BigDecimal高精度計算,不過,看到20分的基礎上,樓主果斷沒有用BigDecimal

代碼:

//source here
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;

int main(){
	int icase;
	cin>>icase;
	double x,y,z;
	string a,b,c;
	for(int i= 1; i<= icase; ++i){
		cin>>x>>a>>y>>b>>z>>c;
		if(a=="m"){
			x*=1000;
		}else if(a=="dm"){
			x*=100;
		}else if(a=="cm"){
			x*=10;
		}else if(a=="um"){
			x/=1000;
		}else if(a=="nm"){
			x/=1000000;
		}
		if(b=="m"){
			y*=1000;
		}else if(b=="dm"){
			y*=100;
		}else if(b=="cm"){
			y*=10;
		}else if(b=="um"){
			y/=1000;
		}else if(b=="nm"){
			y/=1000000;
		}
		double tt= x*z/y;
		printf("Case %d: %.2lfpx\n",i, tt);
	}
}



第二題:

描述

有一個N個節點的樹,其中點1是根。初始點權值都是0。

一個節點的深度定義爲其父節點的深度+1,。特別的,根節點的深度定義爲1。

現在需要支持一系列以下操作:給節點u的子樹中,深度在l和r之間的節點的權值(這裏的深度依然從整個樹的根節點開始計算),都加上一個數delta。

問完成所有操作後,各節點的權值是多少。


爲了減少巨大輸出帶來的開銷,假設完成所有操作後,各節點的權值是answer[1..N],請你按照如下方式計算出一個Hash值(請選擇合適的數據類型,注意避免溢出的情況)。最終只需要輸出這個Hash值即可。


MOD =1000000007; // 10^9 + 7

MAGIC= 12347;

Hash =0;

For i= 1 to N do

   Hash = (Hash * MAGIC + answer[i]) mod MOD;

EndFor


輸入

第一行一個整數T (1 ≤ T ≤ 5),表示數據組數。

接下來是T組輸入數據,測試數據之間沒有空行。

每組數據格式如下:

第一行一個整數N (1 ≤ N ≤ 105),表示樹的節點總數。

接下來N - 1行,每行1個數,a (1 ≤ a ≤ N),依次表示2..N節點的父親節點的編號。

接下來一個整數Q(1 ≤ Q ≤ 105),表示操作總數。

接下來Q行,每行4個整數,u, l, r, delta (1 ≤ u ≤ N, 1 ≤ l ≤ r ≤ N, -109 ≤ delta ≤ 109),代表一次操作。


輸出

對每組數據,先輸出一行“Case x: ”,x表示是第幾組數據,然後接這組數據答案的Hash值。


數據範圍


小數據:1 ≤ N, Q ≤ 1000

大數據:1 ≤ N, Q ≤ 105


分析:

果斷地先根據根,進行廣度遍歷,求出層次,然後修改值的時候也是層次遍歷,樓主當時沒想過其它什麼算法,感覺這樣可能 AC,就寫了如下代碼:

//source here

#include <iostream>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <queue>
using namespace std;

const int NODE_COUNT= 100001;
vector<int>	child[NODE_COUNT];
long long	val[NODE_COUNT];
long long	parent[NODE_COUNT];
int		level[NODE_COUNT];
int node;
long long MOD =1000000007; // 10^9 + 7

long long MAGIC= 12347;
void BuildLevel();
void Change(int u,int r,int l, int delta);
long long hash();
int main(){
	int icase;
	cin>>icase;
	int c;
	for(int i= 1; i<= icase; ++i){
		scanf("%d",&node);
		memset(val,0,NODE_COUNT*sizeof(int));
		for(int l= 0; l< node; ++l){//empty child
			child[l].clear();
		}
		level[0]= 1;
		for(int l= 1; l< node; ++l){
			scanf("%d",&c);
			--c;
			parent[l]=c;
			child[c].push_back(l);
		}
		BuildLevel();
		int r,l,delta,u;
		int x;
		scanf("%d",&x);
		while(x--){
			cin>>u>>l>>r>>delta;
			--u;
			Change(u,l,r,delta);
		}
		cout<<"Case "<<i<<": "<<::hash()<<endl;
	}
}

void Change(int u,int l,int r, int delta){
	queue<int> q;
	q.push(u);
	int now;
	while(!q.empty()){
		now= q.front();
		vector<int>& lhs= child[now];
		q.pop();
		if(level[now]>= l && level[now]<= r){//[l,r]
			val[now]+=delta;

		}else if(level[now]>r){
			continue;
		}
		for(int i= 0; i< lhs.size();++i){
			q.push(lhs[i]);
		}
	}
}

long long hash(){
	long long s= 0;
	for(int i= 0; i< node; ++i){
		s= (s*MAGIC+val[i])%MOD;
	}
	return s;
}

void BuildLevel(){
	queue<int> q;
	level[0]= 1;
	q.push(0);
	int now;
	while(!q.empty()){
		now= q.front();
		q.pop();
		vector<int>& lhs= child[now];
		for(int i= 0; i< lhs.size(); ++i){
			level[lhs[i]]= level[now]+1;
			q.push(lhs[i]);
		}
	}
}

第三題:

描述

A市是一個高度規劃的城市,但是科技高端發達的地方,居民們也不能忘記運動和鍛鍊,因此城市規劃局在設計A市的時候也要考慮爲居民們建造一個活動中心,方便居住在A市的居民們能隨時開展運動,鍛鍊強健的身心。

城市規劃局希望活動中心的位置滿足以下條件:

1. 到所有居住地的總距離最小。

2. 爲了方便活動中心的資源補給和其他器材的維護,活動中心必須建設在A市的主幹道上。


爲了簡化問題,我們將A市擺在二維平面上,城市的主幹道看作直角座標系平的X軸,城市中所有的居住地都可以看成二維平面上的一個點。

現在,A市的城市規劃局希望知道活動中心建在哪兒最好。


輸入

第一行包括一個數T,表示數據的組數。

接下來包含T組數據,每組數據的第一行包括一個整數N,表示A市共有N處居住地

接下來N行表示每處居住地的座標。


輸出

對於每組數據,輸出一行“Case X: Y”,其中X表示每組數據的編號(從1開始),Y表示活動中心的最優建造位置。我們建議你的輸出保留Y到小數點後6位或以上,任何與標準答案的絕對誤差或者相對誤差在10-6以內的結果都將被視爲正確。


數據範圍

小數據:1 ≤ T ≤ 1000, 1 ≤ N ≤ 10

大數據:1 ≤ T ≤ 10, 1 ≤ N ≤ 105

對於所有數據,座標值都是整數且絕對值都不超過106


解析:

果斷地,求導數,導數爲0的值就是我們要求的,我們會發現導數是單調的(導數的導數大於0),然後果斷二分,代碼如下:

//source here
#include <iostream>
#include <vector>
#include <stdio.h>
#include <utility>
#include <algorithm>
#include <string>
#include <math.h>
using namespace std;
vector<pair<double,double> > point;
const double EPSI= 0.000000001;

bool operator < (const pair<double,double>& lhs, const pair<double,double>& rhs){
	return lhs.first< rhs.first;
}

bool Check(double x);

int main(){
	int icase;
	cin>>icase;
	pair<double,double> pt;
	int ic;
	double l,h,mid;
	for(int i= 1; i<= icase; ++i){
		cin>>ic;
		point.clear();
		while(ic--){
			cin>>pt.first>>pt.second;
			point.push_back(pt);
		}
		sort(point.begin(),point.end());
		l= point[0].first;
		h= point[point.size()-1].first;
		while(fabs(l-h)>= EPSI){
			mid= (l+h)/2;
			if(Check(mid)){//>=0
				h= mid;
			}else{
				l= mid;
			}
		}
		printf("Case %d: %.6lf\n",i,mid);
	}
}

bool Check(double x){
	double sum= 0;
	int len= point.size();
	double a,b;
	for(int i= 0; i< len; ++i){
		a= x-point[i].first;
		b= sqrt(a*a+(point[i].second*point[i].second));
		sum+=a/b;
	}
	return sum>= 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章