2014编程之美初赛第一场
题目1 : 焦距
描述
一般来说,我们采用针孔相机模型,也就是认为它用到的是小孔成像原理。
在相机坐标系下,一般来说,我们用到的单位长度,不是“米”这样的国际单位,而是相邻像素的长度。而焦距在相机坐标系中的大小,是在图像处理领域的一个非常重要的物理量。
假设我们已经根据相机参数,得到镜头的物理焦距大小(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)
- 样例输入
-
2 5.4mm 5.27mm 1600px 5400um 0.00527m 1600px
- 样例输出
-
Case 1: 1639.47px Case 2: 1639.47px
解题思路:
为了方便,我们可以用stringstream字符串流进行string流的读入。
我们需要用long double避免double不够位数的问题。
格式输出:
cout<<setiosflags(ios::fixed)<<setprecision(2)<<ans<<"px"<<endl;
#include <set> #include <map> #include <list> #include <cmath> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <complex> #include <fstream> #include <iostream> #include <algorithm> #include<iomanip> using namespace std; typedef long long ll; typedef unsigned long long ull; #define debug puts("yejinru") #define rep(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define REP(i,a,b) for(int i=a;i<=b;i++) #define foreach(i,vec) for(int i=0;i<(int)vec.size();i++) #define pb push_back #define RD(n) scanf("%d",&n) #define RD2(x,y) scanf("%d%d",&x,&y) #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w) #define All(vec) vec.begin(),vec.end() #define MP make_pair #define PII pair<int,int> #define PQ priority_queue #define cmax(x,y) x = max(x,y) #define cmin(x,y) x = min(x,y) #define Clear(x) memset(x,0,sizeof(x)) #define lson rt<<1 #define rson rt<<1|1 #define SZ(x) x.size() /* #pragma comment(linker, "/STACK:1024000000,1024000000") int ssize = 256 << 20; // 256MB char *ppp = (char*)malloc(ssize) + ssize; __asm__("movl %0, %%esp\n" :: "r"(ppp) ); */ char IN; bool NEG; inline void Int(int &x){ NEG = 0; while(!isdigit(IN=getchar())) if(IN=='-')NEG = 1; x = IN-'0'; while(isdigit(IN=getchar())) x = x*10+IN-'0'; if(NEG)x = -x; } inline void LL(ll &x){ NEG = 0; while(!isdigit(IN=getchar())) if(IN=='-')NEG = 1; x = IN-'0'; while(isdigit(IN=getchar())) x = x*10+IN-'0'; if(NEG)x = -x; } /******** program ********************/ long double in(string a){ int id = 1; if( !isdigit(a[ a.size()-2 ]) ) id = 2; stringstream ccin(a.substr(0,a.size()-id)); long double d; ccin>>d; if(id==1) d *= 1000; else{ id = a.size()-2; if(a[id]=='d') d *= 100; else if(a[id]=='c') d *= 10; else if(a[id]=='m') d *= 1; else if(a[id]=='u') d *= 0.001; else d /= 1000*1000; } return d; } int main(){ #ifndef ONLINE_JUDGE freopen("sum.in","r",stdin); //freopen("sum.out","w",stdout); #endif int ncase,cnt = 0; RD(ncase); while(ncase--){ string a,b,c; cin>>a>>b>>c; long double x = in(a); long double y = in(b); stringstream dd(c.substr(0,c.size()-2)); long double z; dd>>z; long double ans = x/y*z; printf("Case %d: ",++cnt); cout<<setiosflags(ios::fixed)<<setprecision(2)<<ans<<"px"<<endl; } return 0; }
题目2 : 树
描述
有一个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值即可。
- 样例输入
-
1 3 1 2 2 1 2 3 1 2 1 1 1
- 样例输出
-
Case 1: 12348
比赛时想到正解前,交了一发爆搜,最后大数据都能过,数据也够弱的,囧。
后来在比赛中想到如下思路,最后也A了。
解题思路如下:
首先遍历整棵树,记录下每个节点的高度。
对于询问(x,l,r,delta),我们把该操作(l,r,delta)放进vector[x]中。
最后,我们遍历一遍整棵树,对于节点x,我们用差分数列、树状数组或线段树进行维护。
差分数列维护的话:
先遍历一遍vector[x],把操作(l,r,delta)添加到深度为[l,r]的区间
foreach(i,vec[x]){ node now = vec[x][i]; int l = now.l; int r = now.r; ll val = now.val; a[l] += val; a[r+1] -= val; }
因为是dfs,所以递归到下一层时,直接累和即为当前节点的值,累和:
a[depth] += a[depth-1];
然后递归遍历x节点的子节点
消除当前节点对其他非子节点的影响,最后把加上的给减掉:
a[depth] = (a[depth]-a[depth-1]+3LL*MOD)%MOD; foreach(i,vec[x]){ node now = vec[x][i]; int l = now.l; int r = now.r; ll val = now.val; a[l] -= val; a[r+1] += val; }
最后代码如下:
#include <set> #include <map> #include <list> #include <cmath> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <complex> #include <fstream> #include <iostream> #include <algorithm> #include<iomanip> using namespace std; typedef long long ll; typedef unsigned long long ull; #define debug puts("yejinru") #define rep(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define REP(i,a,b) for(int i=a;i<=b;i++) #define foreach(i,vec) for(int i=0;i<(int)vec.size();i++) #define pb push_back #define RD(n) scanf("%d",&n) #define RD2(x,y) scanf("%d%d",&x,&y) #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w) #define All(vec) vec.begin(),vec.end() #define MP make_pair #define PII pair<int,int> #define PQ priority_queue #define cmax(x,y) x = max(x,y) #define cmin(x,y) x = min(x,y) #define Clear(x) memset(x,0,sizeof(x)) #define lson rt<<1 #define rson rt<<1|1 #define SZ(x) x.size() /* #pragma comment(linker, "/STACK:1024000000,1024000000") int ssize = 256 << 20; // 256MB char *ppp = (char*)malloc(ssize) + ssize; __asm__("movl %0, %%esp\n" :: "r"(ppp) ); */ char IN; bool NEG; inline void Int(int &x){ NEG = 0; while(!isdigit(IN=getchar())) if(IN=='-')NEG = 1; x = IN-'0'; while(isdigit(IN=getchar())) x = x*10+IN-'0'; if(NEG)x = -x; } inline void LL(ll &x){ NEG = 0; while(!isdigit(IN=getchar())) if(IN=='-')NEG = 1; x = IN-'0'; while(isdigit(IN=getchar())) x = x*10+IN-'0'; if(NEG)x = -x; } /******** program ********************/ const int MAXN = 1e5+5; struct node{ int l,r; ll val; node(){} node(int _l,int _r,ll _val){ l = _l; r = _r; val = _val; } }; vector<int> adj[MAXN]; vector< node > vec[MAXN]; ll delta[MAXN]; int dep[MAXN]; const int MOD =1000000007; // 10^9 + 7 const int MAGIC= 12347; void dfs_init(int x,int d){ // 初始化每个节点的深度 dep[x] = d; foreach(i,adj[x]) dfs_init(adj[x][i],d+1); } ll a[MAXN]; void dfs(int x,int depth){ foreach(i,vec[x]){ node now = vec[x][i]; int l = now.l; int r = now.r; ll val = now.val; a[l] += val; // 添加 a[r+1] -= val; } a[depth] = (a[depth]+a[depth-1]+3LL*MOD)%MOD; // 差分数列 delta[x] = a[depth]; foreach(i,adj[x]) dfs(adj[x][i],depth+1); a[depth] = (a[depth]-a[depth-1]+3LL*MOD)%MOD; foreach(i,vec[x]){ node now = vec[x][i]; int l = now.l; int r = now.r; ll val = now.val; a[l] -= val; // 消除对后面影响 a[r+1] += val; } } int main(){ #ifndef ONLINE_JUDGE freopen("sum.in","r",stdin); //freopen("sum.out","w",stdout); #endif int ncase,cnt = 0; RD(ncase); while(ncase--){ printf("Case %d: ",++cnt); int n,pa,q; RD(n); rep1(i,n){ adj[i].clear(); vec[i].clear(); } memset(delta,0,sizeof(delta)); for(int i=2;i<=n;i++){ RD(pa); adj[pa].pb(i); } dfs_init(1,1); RD(q); int l,r,x,d; while(q--){ RD4(x,l,r,d); vec[x].pb( node(l,r,d) ); } memset(a,0,sizeof(a)); dfs(1,1); ll ans = 0; rep1(i,n) ans = (ans*MAGIC+delta[i]+3LL*MOD)%MOD; cout<<ans<<endl; } return 0; }
题目3 : 活动中心
描述
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)
- 样例输入
-
1 3 1 1 2 2 3 3
- 样例输出
-
Case 1: 1.678787
解题思路:
三分,跟去年编程之美这题2013編程之美 集会 三分基本一样。注意下迭代次数。
#include <set> #include <map> #include <cmath> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include<iomanip> using namespace std; typedef long long ll; typedef unsigned long long ull; #define lx(x) (x<<1) #define rx(x) (x<<1|1) #define debug puts("here") #define rep(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define REP(i,a,b) for(int i=a;i<=b;i++) #define foreach(i,vec) for(unsigned i=0;i<vec.size();i++) #define pb push_back #define RD(n) scanf("%d",&n) #define RD2(x,y) scanf("%d%d",&x,&y) #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w) /******** program ********************/ const int MAXN = 1e5+5; const int INF = 1e8; struct node{ double x,y; }p[MAXN]; int n; long double dis(long double x,long double y){ return sqrt( x*x+y*y ); } long double cal(long double now){ long double tmp = 0; rep(i,n) tmp += dis(p[i].x-now,p[i].y); return tmp; } int main(){ #ifndef ONLINE_JUDGE freopen("sum.in","r",stdin); //freopen("sum.out","w",stdout); #endif int ncase; RD(ncase); rep1(Ncase,ncase){ printf("Case %d: ",Ncase); RD(n); long double L = INF,R = -INF; rep(i,n){ scanf("%lf%lf",&p[i].x,&p[i].y); L = min(L,(long double)p[i].x); R = max(R,(long double)p[i].x); } long double l = 0,r = 1; long double px1,px2; rep(step,50){ long double m1 = (2*l+r)/3; long double m2 = (l+2*r)/3; px1 = L*(1-m1)+R*m1; px2 = L*(1-m2)+R*m2; long double tmp = cal(px1); long double ret = cal(px2); if(tmp>ret) l = m1; else r = m2; } if(px1<0&&fabs(px1)<1e-9) // 判斷是否會出現-0.000000 px1 *= -1.0; cout<<setiosflags(ios::fixed)<<setprecision(8)<<px1<<endl; } return 0; }