website: http://hihocoder.com/contest/msbop2014r2a
P1 : 焦距
-
2 5.4mm 5.27mm 1600px 5400um 0.00527m 1600px
Sample Output
-
Case 1: 1639.47px Case 2: 1639.47px
題目描述
一般來說,我們採用針孔相機模型,也就是認為它用到的是小孔成像原理。
在相機坐標系下,一般來說,我們用到的單位長度,不是「米」這樣的國際單位,而是相鄰圖元的長度。而焦距在相機坐標系中的大小,是在影像處理領域的一個非常重要的物理量。
假設我們已經根據相機參數,得到鏡頭的物理焦距大小(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為焦距在相機坐標系中的大小(focal length in pixels),保留小數點後2位有效數字,四捨五入取整。
資料範圍
對於小資料:focal length on earth和CCD width on earth單位都是毫米(mm)
對於大資料:長度單位還可能為米(m), 公寸(dm), 釐米(cm), 毫米(mm), 微米(um),納米(nm)
#include <cstdio>
#include <cstring>
using namespace std;
double adjust(char s[], double a) {
if (strcmp(s, "m") == 0)
return a * 1e9;
else if (strcmp(s, "dm") == 0)
return a * 1e8;
else if (strcmp(s, "cm") == 0)
return a * 1e7;
else if (strcmp(s, "mm") == 0)
return a * 1e6;
else if (strcmp(s, "um") == 0)
return a * 1e3;
else if (strcmp(s, "nm") == 0)
return a;
return a;
}
int main() {
int T;
scanf("%d", &T);
for (int casenum = 1; casenum <= T; ++casenum) {
double a, b, c;
char s[10], t[10];
scanf("%lf%s%lf%s%lf%*s", &a, s, &b, t, &c);
a = adjust(s, a);
b = adjust(t, b);
printf("Case %d: %.2lfpx\n", casenum, a / b * c);
}
return 0;
}
P2 : 樹
-
1 3 1 2 2 1 2 3 1 2 1 1 1
Sample Output
-
Case 1: 12348
題目描述
有一個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
樣例解釋
點1的子樹中有1,2,3三個節點。其中深度在2-3之間的是點2和點3。
點2的子樹中有2,3兩個節點。其中沒有深度為1的節點。
所以,執行完所有操作之後,只有2,3兩點的權值增加了1。即答案是0 1 1。再計算對應的Hash值即可。
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const long long MOD = 1000000007;
const long long MAGIC = 12347;
int calc(const int u, const vector<int> &depth, const vector<vector<int> > &child,
vector<int> &height) {
const int n = child[u].size();
if (n == 0) {
height[u] = depth[u];
return height[u];
}
int h = 0;
for (int i = 0; i < n; ++i)
h = max(h, calc(child[u][i], depth, child, height));
height[u] = h;
return h;
}
void add(const int u, const int l, const int r, const int delta,
const vector<int> &depth, const vector<int> &height, const vector<vector<int> > &child,
vector<int> &weight) {
if (depth[u] >= l) weight[u] += delta;
if (depth[u] == r) return;
int n = child[u].size();
for (int i = 0; i < n; ++i) {
int v = child[u][i];
if (height[v] >= l && depth[v] <= r)
add(v, l, r, delta, depth, height, child, weight);
}
}
int main() {
int T;
scanf("%d", &T);
for (int casenum = 1; casenum <= T; ++casenum) {
int n, qnum;
scanf("%d", &n);
vector<int> weight(n, 0);
vector<vector<int> > child(n, vector<int>());
for (int i = 1; i < n; ++i) {
int fa;
scanf("%d", &fa);
child[fa - 1].push_back(i);
}
vector<int> depth(n, 0), height(n, 0);
depth[0] = 1;
queue<int> q;
q.push(0);
while (!q.empty()) {
int u = q.front();
q.pop();
int m = child[u].size();
for (int i = 0; i < m; ++i) {
int v = child[u][i];
depth[v] = depth[u] + 1;
q.push(v);
}
}
calc(0, depth, child, height);
scanf("%d", &qnum);
while (qnum--) {
int u, l, r, delta;
scanf("%d%d%d%d", &u, &l, &r, &delta);
--u;
if (height[u] >= l && depth[u] <= r)
add(u, l, r, delta, depth, height, child, weight);
}
long long ans = 0;
for (int i = 0; i < n; ++i)
ans = (ans * MAGIC + weight[i]) % MOD;
printf("Case %d: %lld\n", casenum, ans);
}
return 0;
}
P3 : 活動中心
-
1 3 1 1 2 2 3 3
Sample Output
-
Case 1: 1.678787
題目描述
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
樣例解釋
樣例1:活動中心的最優建造位置為(1.678787,0)
#include <cstdio>
#include <cmath>
#include <cfloat>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
struct Point{
double x, y;
}p[100000];
double area(double x, int n) {
double res = 0;
for (int i = 0; i < n; ++i)
res += sqrt((p[i].x - x) * (p[i].x - x) + p[i].y * p[i].y);
return res;
}
int main() {
int T;
scanf("%d", &T);
for (int casenum = 1; casenum <= T; ++casenum) {
int n;
scanf("%d", &n);
double low = DBL_MAX, high = -DBL_MAX;
for (int i = 0; i < n; ++i) {
scanf("%lf%lf", &p[i].x, &p[i].y);
low = min(low, p[i].x);
high = max(high, p[i].x);
}
while (low + eps < high) {
double mid = (low + high) / 2;
double tmp = mid + 1e-5; // 1e-6 WA, better use 三分
double a = area(mid, n), b = area(tmp, n);
if (a < b)
high = mid;
else
low = mid;
}
printf("Case %d: %.6lf\n", casenum, high);
}
return 0;
}