Codeforces 2
A. Winner
题目地址:http://codeforces.com/contest/2/problem/A
题目大意:给出每一次比赛的得分情况,问最后得分最高的人。若最后分数同样,则输出分数同样的人中第一个分数不小于最后最高分数的人。
算法讨论:用STL中的map和set维护就可以。
Code:
#include <iostream> #include <map> #include <set> #include <string> #define N 1000 using namespace std; int n,Max,score[N+10]; string name[N+10]; set<string> Set; map<string,int> sum; int main(){ cin>>n; for (int i=1;i<=n;++i){ cin>>name[i]>>score[i]; sum[name[i]]+=score[i]; } for (map<string,int>::iterator i=sum.begin();i!=sum.end();++i) if (i->second>Max) Max=i->second; for (map<string,int>::iterator i=sum.begin();i!=sum.end();++i) if (i->second==Max) Set.insert(i->first); sum.clear(); for (int i=1;i<=n;++i) if (Set.count(name[i])){ sum[name[i]]+=score[i]; if (sum[name[i]]>=Max){ cout<<name[i]<<endl; return 0; } } }
B. The least round way
题目地址:http://codeforces.com/contest/2/problem/B
题目大意:给出一个矩阵,求从左上角到右下角的一条路径,使得路径上的数的乘积后的0最少。
算法讨论:
DP之。
分别求解从左上角到某一点的乘积中2的个数和5的个数,则0的个数为2的个数和5的个数中的较小值。
须要注意的是含0的情况。方法是读入的时候把0变成10,DP之,若答案大于1则使路径经过0就可以。
Code:
#include <cstdio> #include <algorithm> #include <stack> #define N 1000 #define oo 0x7f7f7f7f using namespace std; int n,x,y,a[N+10][N+10],cnt[N+10][N+10][2],dp[N+10][N+10][2]; bool f; stack<char> S; int main(){ scanf("%d",&n); for (int i=0;i<=n;++i) for (int j=0;j<=n;++j) dp[i][j][0]=dp[i][j][1]=oo; for (int i=1;i<=n;++i) for (int j=1;j<=n;++j){ scanf("%d",&a[i][j]); if (!a[i][j]) f=1,x=i,y=j,a[i][j]=10; for (int t=a[i][j];t%2==0;t/=2,cnt[i][j][0]++); for (int t=a[i][j];t%5==0;t/=5,cnt[i][j][1]++); } dp[1][1][0]=cnt[1][1][0]; dp[1][1][1]=cnt[1][1][1]; for (int i=1;i<=n;++i) for (int j=1;j<=n;++j){ if (i==1 && j==1) continue; dp[i][j][0]=min(dp[i-1][j][0],dp[i][j-1][0])+cnt[i][j][0]; dp[i][j][1]=min(dp[i-1][j][1],dp[i][j-1][1])+cnt[i][j][1]; } if (f && min(dp[n][n][0],dp[n][n][1])>1){ printf("1\n"); for (int i=1;i<x;++i) printf("D"); for (int i=1;i<y;++i) printf("R"); for (int i=x;i<n;++i) printf("D"); for (int i=y;i<n;++i) printf("R"); return 0; } printf("%d\n",min(dp[n][n][0],dp[n][n][1])); if (dp[n][n][0]<dp[n][n][1]){ int i=n,j=n; do{ if (i>1 && dp[i][j][0]==dp[i-1][j][0]+cnt[i][j][0]) i--,S.push('D'); else if (j>1) j--,S.push('R'); }while (i!=1 || j!=1); } else{ int i=n,j=n; do{ if (i>1 && dp[i][j][1]==dp[i-1][j][1]+cnt[i][j][1]) i--,S.push('D'); else if (j>1) j--,S.push('R'); }while (i!=1 || j!=1); } while (!S.empty()) printf("%c",S.top()),S.pop(); puts(""); return 0; }
C. Commentator problem
题目地址:http://codeforces.com/contest/2/problem/C
题目大意:给三个圆(互不包括),求一个点,使得这个点看三个圆的视角同样。
算法讨论:模拟退火。
初始状态为三个圆心的中心,估价函数为三个视角的一半的正弦值的平方和。
Code:
#include <cstdio> #include <cmath> #define N 300000 #define eps 1e-20 using namespace std; int xa,ya,ra,xb,yb,rb,xc,yc,rc; double x,y,v,delta; const int dx[]={0,0,1,-1},dy[]={1,-1,0,0}; inline double sqr(double x){ return x*x; } inline double dist(double x1,double y1,double x2,double y2){ return sqrt(sqr(x1-x2)+sqr(y1-y2)); } inline double value(double x,double y){ double a1=ra/dist(x,y,xa,ya),a2=rb/dist(x,y,xb,yb),a3=rc/dist(x,y,xc,yc); return sqr(a1-a2)+sqr(a2-a3)+sqr(a1-a3); } int main(){ scanf("%d%d%d",&xa,&ya,&ra); scanf("%d%d%d",&xb,&yb,&rb); scanf("%d%d%d",&xc,&yc,&rc); x=(double)(xa+xb+xc)/3; y=(double)(ya+yb+yc)/3; v=value(x,y); delta=1; for (int i=0;i<N && v>eps;++i){ bool f=0; for (int j=0;j<4;++j){ double xx=x+delta*dx[j],yy=y+delta*dy[j],vv; if ((vv=value(xx,yy))<v) v=vv,x=xx,y=yy,f=1; } if (!f) delta*=.5; } if (value(x,y)<=eps) printf("%0.5lf %0.5lf\n",x,y); return 0; }
By Charlie Pan
Mar 4,2014