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
");
		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
",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
",x,y);
	return 0;
}


By Charlie Pan

Mar 4,2014

原文地址:https://www.cnblogs.com/blfbuaa/p/6971107.html