您的位置:首页 > 其它

codeforce CROC-MBTU 2012, Final Round (Online version, Div. 2)

2012-11-27 23:09 274 查看
点击打开链接

A

思路:枚举判断

分析:题目要求找到最少的划分数,那么我们只要对这n个数进行枚举判断即可。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

#define MAXN 110

int n;
int value[MAXN];

int main(){
while(scanf("%d" , &n) != EOF){
for(int i = 0 ; i < n ; i++)
scanf("%d" , &value[i]);
int sum , num , tmp;
int ans[MAXN];
sum = 0;
num = tmp = 0;
memset(ans , 0 , sizeof(ans));
for(int i = 0 ; i < n ; i++){
if(value[i] < 0){
if(num+1 == 3){
ans[sum] = tmp;
sum++;
tmp = num = 1;
}
else{
num++;
tmp++;
}
}
else
tmp++;
}
ans[sum++] = tmp;
printf("%d\n%d" , sum , ans[0]);
for(int i = 1 ; i < sum ; i++)
printf(" %d" , ans[i]);
printf("\n");
}
return 0;
}



B
思路:模拟题

分析:注意以下几种情况

1 没有::

2 ::类型

3 ::05类型

4 05::类型

5 05::05类型

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define MAXN 1010

int n;
char str[MAXN];

int main(){
int mark , pre;
while(scanf("%d" , &n) != EOF){
for(int i = 0 ; i < n ; i++){
scanf("%s" , str);
int left , right , pos;
left = right = 0;
pos = -1;
mark = 0;
int len = strlen(str);
for(int i = 0 ; i < len-1 ; i++){
if(str[i] == ':' && str[i+1] == ':'){
pos = i;
mark = 1;
if(i != 0)
left++;
if(i+1 != len-1)
right++;
i++;
continue;
}
else if(str[i] == ':' && !mark)
left++;
else if(str[i] == ':' && mark)
right++;
}
if(pos == -1){
pre = 0;
for(int i = 0 ; i < len ; i++){
if(str[i] == ':' || i == len-1){
if(i == len-1)
i = len;
int tmp = 4-(i-pre);
for(int j = 0 ; j < tmp ;j++)
printf("0");
for(int j = pre ; j < i ; j++)
printf("%c" , str[j]);
if(i != len)
printf(":");
pre = i+1;
}
}
printf("\n");
}
else{
int num = 8-left-right;
if(num == 8)
printf("0000:0000:0000:0000:0000:0000:0000:0000\n");
else{
pre = 0;
for(int i = 0 ; i < len ; i++){
if(i != pos+1){
if(i != 0 && str[i] == ':' || i == len-1){
if(i == len-1)
i = len;
int tmp = 4-(i-pre);
for(int j = 0 ; j < tmp ; j++)
printf("0");
for(int j = pre ; j < i ; j++)
printf("%c" , str[j]);
if(i != pos && i != len)
printf(":");
if(i != pos)
pre = i+1;
}
}
else{
for(int j = 0 ; j < num ; j++){
if(j == 0 && pos == 0)
printf("0000");
else
printf(":0000");
}
pre = i+1;
if(i+1 != len)
printf(":");
}
}
printf("\n");
}
}
}
}
return 0;
}


C
思路:贪心

分析:

1 题目要求的是去掉某个数之和得到的数字串的最少的变化的次数

2 首先我们可以利用c++的unique函数把原序列变成不重复的序列。题目要求最少的变化次数,如果我们去枚举k的话,那么肯定是要TLE的o(n^2),所以我们可以换个角度思考,如果我们能够得到去掉某个数之后原序列变化减少了几次,那么我们找到这个减少最多就等价于去掉该数后最少的变化次数。

3 所以我们利用o(n)的时间去枚举上面得到的不重复序列,然后遇到每一个数就判断将该类数去掉之和变化数减少了几次。

比如当前为1 2 1,那么去掉2之和减少了2次, 如果当前为1 2 3那么去掉2之后减少了1次,所以我们需要注意判断这些情况。

4 第一个数和最后一个数特殊判断

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define MAXN 100010

int n , k;
int value[MAXN];
int vis[MAXN];

int main(){
while(scanf("%d%d" , &n , &k) != EOF){
for(int i = 0 ; i < n ; i++)
scanf("%d" , &value[i]);
int tmp = unique(value , value+n)-value;
memset(vis , 0 , sizeof(vis));
if(value[0] != value[1])
vis[value[0]]++;
if(vis[tmp-2] != value[tmp-1])
vis[value[tmp-1]]++;
for(int i = 1 ; i < tmp-1 ; i++){
if(value[i-1] == value[i+1])
vis[value[i]] += 2;
else
vis[value[i]]++;
}
int ans = 1;
for(int i = 1 ; i <= k ; i++){
if(vis[i] > vis[ans])
ans = i;
}
printf("%d\n" , ans);
}
return 0;
}



D
思路:贪心

分析:

1 题目要求的是给定两条直线L1 , L2和直线上的点已经不再直线上的两个点A,B,现在A到L1有n个路,B到L2与m条路,问|AB| = |AL1|+|L1L2|+|L2B|的最小值

2 题目给定的数据已经是排好序的,看以下这张图



看图上面这些点的编号都是随着y的增大而变大,如图假设(a+1+x2)> (b+2+x2),那么我们选择的左边的点肯定是是上面点,再看如果 (b+2+x2) > (b+3+x1) 那么我们右边选择的是上面的点。所以我们可以通过这样去枚举求出最后的最小值。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<utility>
using namespace std;

#define MAXN 100010
#define eps 1e-6

int n , m , a , b;
struct Point{
int x;
int y;
double dis;
};
Point west[MAXN] , east[MAXN];

/*求两点之间的距离*/
double Distance(Point p1 , Point p2){
double tmpx = 1.0*(p1.x-p2.x)*(p1.x-p2.x);
double tmpy = 1.0*(p1.y-p2.y)*(p1.y-p2.y);
return sqrt(tmpx+tmpy);
}

void solve(){
int i , j;
j = 1;
pair<int , int>pi;
double ans = 1e9;
for(i = 1 ; i <= m ; i++){
while(j < n && (west[j].dis+Distance(east[i] , west[j])+east[i].dis) > (west[j+1].dis+Distance(east[i] , west[j+1])+east[i].dis))
j++;
double tmp = west[j].dis+Distance(east[i] , west[j])+east[i].dis;
if(ans > tmp){/*更新ans*/
ans = tmp;
pi.first = j;
pi.second = i;
}
}
printf("%d %d\n" , pi.first , pi.second);
}

int main(){
Point p1 , p2;
while(scanf("%d%d%d%d" , &n , &m , &a , &b) != EOF){
p1.x = p1.y = 0;
p2.x = a;
for(int i = 1 ; i <= n ; i++){
scanf("%d" , &p2.y);
west[i].x = a , west[i].y = p2.y;
west[i].dis = Distance(p1 , p2);
}
for(int i = 1 ; i <= m ; i++){
scanf("%d" , &east[i].y);
east[i].x = b;
}
for(int i = 1 ; i <= m ; i++)
scanf("%lf" , &east[i].dis);
solve();
}
return 0;
}



E

思路:暴力

分析:

1 题目要求从左上角走到最低下一行的最短的时间。

2 我们可以直接暴力枚举每一行,然后维护一个位置。但是我们要注意的是,因为在某一行之内可能会无限的走,因此我们需要判断如果两次碰到“#”就是不能走了,还有中间要加一些优化不然会TLE。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long int64;
const int N = 110;
const int M = 10010;

int n , m;
char mat
[M];
int dir[2] = {-1 , 1};

int64 solve(){
int64 ans = 0;
int x = 0 , y = 0 , d = 1;
bool isLeft = true , isRight = true;
int pos[2] = {0 , 0};

while(true){
if(!isLeft && !isRight)
return -1;
if(x == n-1)
return ans;
if(mat[x+1][y] == '.'){
ans++ ; x++;
isLeft = isRight = true;
pos[0] = pos[1] = y;
}
else if(y == pos[d]){
int ty = y+dir[d];
ans++;
if(ty < 0 || ty >= m || mat[x][ty] == '#'){
if(d == 0)
isLeft = false;
else
isRight = false;
d ^= 1;
}
else{
pos[d] += dir[d];
if(mat[x][ty] == '.')
y += dir[d];
else
d ^= 1;
}
}
else{
ans += (int64)abs((int64)pos[d]-(int64)y);
y = pos[d];
}
}
return -1;
}

int main(){
while(scanf("%d%d%*c" , &n , &m) != EOF){
for(int i = 0 ; i < n ; i++)
gets(mat[i]);
int64 ans = solve();
if(ans == -1)
puts("Never");
else
cout<<ans<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: