codeforces 2A.Winner
codeforces 2B.The least round way
codeforces 2C.Commentator problem
这期题目想对感觉较难 A敲了十多分钟 B是想了很久才开始写的中间TLE无数次 C完全懵逼 不过最后发现用爬山算法?/模拟退火可以求解 拖了好几天今天终于把C好好的敲了一下 现在送上题解
题目链接:http://codeforces.com/contest/2/problem/A
题解:输入选手姓名和分数 求最后得分最高的人 然后注意是分数最高可能很多人取第一个达到这个分数的人 然后分数可能负数思路比较清晰 map简单应用 第一次循环求出所有人的最后得分 然后最后得分中取出得分最高的人 最后重新判定一下谁先得到这个分数
AC代码:
#include
using namespace std;
map mp, m;
vector vec;
vector ve;
int ma = -0xffffff;
string winer;
int main() {
string str;
int score;
int n;
cin >> n;
getchar();
for(int i = 0; i > str >> score;
mp[str] += score;
vec.push_back(str);
ve.push_back(score);
}
map::iterator it;
for(it = mp.begin(); it != mp.end(); ++it) {
ma = max(it->second, ma);
}
for(int i = 0; i < n; ++i) {
m[vec[i]] += ve[i];
if(m[vec[i]] >= ma && mp[vec[i]] == ma) {
cout << vec[i] << endl;
break;
}
}
return 0;
}
题目链接:http://codeforces.com/contest/2/problem/B
题解:从左上角到右下角经过的数字的乘积最后至少有几个0dp 一个记录经过当前点最少的约数2的数目 一个记录经过当前点最少的约数5的数目 然后取抵达最后一个点2和5的数目最少的那个 TLE无数次 然后其实只是因为一个0的判断未跳出
AC代码:
#include
using namespace std;
const int inf = 0xffffff;
const int maxn = 1010;
int dp[maxn][maxn][2]; //记录得到当前点最少的2和5的数目
int dir[maxn][maxn][2]; //方向
int num[maxn][maxn][2]; //当前点2和5的数目
int n;
bool mark;
int cnt;
void print(int x, int y, int k);
int main() {
scanf("%d", &n);
memset(num, 0, sizeof(num)); //初始化
memset(dir, 0, sizeof(dir)); //初始化
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
int tmp;
scanf("%d", &tmp);
dp[i][j][0] = inf;
dp[i][j][1] = inf;
if(tmp == 0) {
mark = true;
cnt = i;
continue;
}
while(tmp % 2 == 0) {
++ num[i][j][0];
tmp /= 2;
}
while(tmp % 5 == 0) {
++ num[i][j][1];
tmp /= 5;
}
}
}
dp[0][0][0] = num[0][0][0];
dp[0][0][1] = num[0][0][1];
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
if(i) {
if(dp[i][j][0] > dp[i-1][j][0] + num[i][j][0]) {
dp[i][j][0] = dp[i-1][j][0] + num[i][j][0];
dir[i][j][0] = 0;
}
if(dp[i][j][1] > dp[i-1][j][1] + num[i][j][1]) {
dp[i][j][1] = dp[i-1][j][1] + num[i][j][1];
dir[i][j][1] = 0;
}
}
if(j) {
if(dp[i][j][0] > dp[i][j-1][0] + num[i][j][0]) {
dp[i][j][0] = dp[i][j-1][0] + num[i][j][0];
dir[i][j][0] = 1;
}
if(dp[i][j][1] > dp[i][j-1][1] + num[i][j][1]) {
dp[i][j][1] = dp[i][j-1][1] + num[i][j][1];
dir[i][j][1] = 1;
}
}
}
}
int k = dp[n-1][n-1][0] > dp[n-1][n-1][1] ? 1 : 0;
if(mark && dp[n-1][n-1][k] > 1) {
puts("1");
for(int i = 1; i <= cnt; ++i) {
printf("D");
}
for(int i = 1; i < n; ++i) {
printf("R");
}
for(int i = cnt+1; i < n; ++i) {
printf("D");
}
puts("");
}
else {
printf("%d\n", dp[n-1][n-1][k]);
print(n-1, n-1, k);
puts("");
}
return 0;
}
void print(int x, int y, int k) { //递归输出
if(x == y && y == 0) {
return ;
}
if(dir[x][y][k] == 0) {
print(x-1, y, k);
printf("D");
}
else if(dir[x][y][k] == 1) {
print(x, y-1, k);
printf("R");
}
}
The Olympic Games in Bercouver are in full swing now. Here everyone has their own objectives: sportsmen compete for medals, and sport commentators compete for more convenient positions to give a running commentary. Today the main sport events take place at three round stadiums, and the commentator's objective is to choose the best point of observation, that is to say the point from where all the three stadiums can be observed. As all the sport competitions are of the same importance, the stadiums should be observed at the same angle. If the number of points meeting the conditions is more than one, the point with the maximum angle of observation is prefered.
Would you, please, help the famous Berland commentator G. Berniev to find the best point of observation. It should be noted, that the stadiums do not hide each other, the commentator can easily see one stadium through the other.
The input data consists of three lines, each of them describes the position of one stadium. The lines have the format x, y, r, where (x, y) are the coordinates of the stadium's center ( - 103 ≤ x, y ≤ 103), and r (1 ≤ r ≤ 103) is its radius. All the numbers in the input data are integer, stadiums do not have common points, and their centers are not on the same line.
Print the coordinates of the required point with five digits after the decimal point. If there is no answer meeting the conditions, the program shouldn't print anything. The output data should be left blank.
0 0 10 60 0 10 30 30 10
30.00000 0.00000
题目链接:http://codeforces.com/contest/2/problem/C
题解:三个圆 不相交 然后求一个点到三个点的视角和最大模拟退火算法 这里用到一个小技巧就是估价函数视角的和的选取 用距离/半径 然后视角和用距离/半径的差的平方的和来代替 精度到一定范围就可以得出答案 这道题是随机算法求解的所以一定注意精度
PS:这道题拖了好久一直不想碰 因为觉得模拟退火理解的不够 好吧其实就是这几天比较懒
AC代码:
#include
using namespace std;
struct Circle {
double x, y, r;
};
const int dy[4] = {-1, 0, 0, 1};
const int dx[4] = {0, -1, 1, 0};
double ang[3];
Circle c[3];
double K(double x) {
return x * x;
}
double Dis(double x, double y, double xx, double yy) {
return sqrt(K(x - xx) + K(y - yy));
}
double Val(double x, double y) { //估价函数
for(int i = 0; i < 3; ++i) {
ang[i] = Dis(x, y, c[i].x, c[i].y) / c[i].r;
}
double val = 0;
for(int i = 0; i < 3; ++i) {
val += K(ang[i] - ang[(i+1) % 3]);
}
return val;
}
int main() {
double x = 0, y = 0;
for(int i = 0; i < 3; ++i) {
scanf("%lf%lf%lf", &c[i].x, &c[i].y, &c[i].r);
x += c[i].x / 3;
y += c[i].y / 3;
}
//模拟退火
double err = Val(x, y);
double step = 1;
for(int tim = 1; tim < 1e5; ++tim) {
bool flag = false;
double X, Y;
for(int i = 0; i < 4; ++i) {
double xx = x + dx[i] * step;
double yy = y + dy[i] * step;
double val = Val(xx, yy);
if(val < err) {
err = val;
flag = true;
X = xx;
Y = yy;
}
}
if(flag) {
x = X;
y = Y;
}
else {
step /= 2;
}
}
if(err < 1e-6) {
printf("%.5f %.5f\n", x, y);
}
return 0;
}