Codeforces Round #375 (Div. 2)

本文总结了五道ACM竞赛题目,包括寻找最优位置、文本分析、演出调整、湖泊填充及图转换等问题,提供了详细的解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

这场的题其实都挺水。。。但是还是只做了4题。。。前面就卡题,确实自己想问题还是不够严谨。。。

A. The New Year: Meeting Friends

题意

数轴上有三个点,问在哪个位置这三个点到它的距离之和最小。。。

思路

这题数据范围很小,才100,当时想都没想就直接暴力了。。。。。其实这题数据完全可以很大很大。。。。这题仔细想想应该会明白,就是最大的减最小的。。。。

代码

我的sb暴力。。

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

int Abs(int x) {
  if(x < 0)
    return -x;
  return x;
}

int main() {
  int x1,x2,x3;
  cin >> x1 >> x2 >> x3;
  int Min = 0x3f3f3f3f;
  for(int i = -100; i <= 200; i++) {
    Min = min(Min, Abs(i - x1) + Abs(i - x2) + Abs(i - x3));
  }
  printf("%d\n", Min);
  return 0;
}

学妹的。。。(学妹零基础也两题。。。我真是。。。)


#include <iostream>
using namespace std;

int main()
{
    int a,b,c;
    cin >> a >> b >> c;
    int t;
    if (a > b )
    {
        t = a;
        a = b;
        b = t;
    }
    if (a > c)
    {
        t = a;
        a = c;
        c = t;
    }
    if (b > c )
    {
        t = b;
        b = c;
        c = t;
    }
    cout << c - a << endl;
        return 0;
}

B. Text Document Analysis

题意

给定一个字符串,里面有单词,有下划线,有括号,下划线可以分隔单词,问括号外面的单词最长的有多长,括号里面单词有几个。。。

思路

其实就是纯模拟,卡了我好久,一直没考虑清楚。。。一开始居然没考虑到最后一个单词后面不跟下划线的情况。。。可以说我的细节考虑上确实很糟糕。。。(小时候常说的粗心,其实是智障。。。)

代码

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

int main() {
  int n;
  cin >> n;
  string s;
  cin >> s;
  int cnt = 0;
  int maxlen = 0;
  int len = 0;
  bool flag = false;
  for(int i = 0; i < n; i++) {
    if((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z'))
      len++;
    else {
      if(flag && len > 0) cnt++;
      else maxlen = max(maxlen, len);
      len = 0;
      if(s[i] == '(') 
        flag = true;
      if(s[i] == ')')
        flag = false;
    }   
  }
  maxlen = max(maxlen,len);
  cout << maxlen << " " << cnt << endl;
  return 0;
}

C. Polycarp at the Radio

题意

这题呢。。就是说一个人看演唱会只喜欢标号为1~m的乐队的节目,但是现在呢,有n个节目,这里面什么乐队的都有。。。这个人神通广大,可以随便改这个演出的乐队,当然改起来很麻烦,所以他也想尽量少改。现在他想把这个演出改成编号为1~m的乐队表演次数最少的表演次数最大化,并且还要知道改动次数最少是多少,和改动后表演节目的列表。。。(语文都还给小学老师了)

思路

其实最小的最大化。。。那么显而易见,大家都平均好啦。。也是说最小值是n/m,假如i乐队表演次数是f[i],那最少改动次数就是sum(f[i] - n/m),本来就大于n/m的不用管,当然,我们只考虑1~m的就行(废话,不是1~m的鸟都不鸟的)。至于怎么改动,我们只要先把能改动的位置存下来,过会想怎么改都行。。。哪些是能改的?>m的肯定可以。还有就是1~m里那些大于演出n/m的(最多改到n/m为止)。

代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#define ll long long
using namespace std;

const int kMaxn = 2000 + 10;

int a[kMaxn],f[kMaxn];
vector<int>pos;

int main() {
  memset(f, 0, sizeof(f));
  int n,m;
  scanf("%d %d", &n, &m);
  int goal = n / m;
  for(int i = 1; i <= n; i++) {
    scanf("%d", &a[i]);
    if(a[i] <= m)
      f[a[i]]++;
  }
  int sum = 0;
  for(int i = 1; i <= m; i++) {
    if(f[i] < goal)
      sum += goal - f[i];
  }
  for(int i = 1; i <= n; i++) {
    if(a[i] > m)
      pos.push_back(i);
    else if(f[a[i]] > goal) {
      f[a[i]]--;
      pos.push_back(i);
    }
  }
  printf("%d %d\n", goal, sum);
  int t = 0;
  for(int i = 1; i <= m; i++) {
    while(f[i] < goal) {
      a[pos[t]] = i;
      f[i]++;
      t++;
    }
  }
  for(int i = 1; i < n; i++)
    printf("%d ", a[i]);
  printf("%d\n", a[n]);
  return 0;
}

D. Lakes in Berland

题意

这题是说要填湖,最后要把湖填得只剩下恰好k个,问最少要用多少土。。。给出的是一个矩阵,*位置是陆地,.位置是湖,最外围和大海联通,这种是填不掉的。。。

思路

我当时想都没想就写了个暴力。。。因为数据很小。。就过了。。。首先先把海的位置全填了,避免干扰。。。然后dfs把所有的湖都取出来,拍个序再去填。。。。完全没什么坑点。。。

代码

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

const int kMaxn = 50 + 5;

int dx[] = {0, 1, -1, 0};
int dy[] = {1, 0, 0, -1};

char a[kMaxn][kMaxn],b[kMaxn][kMaxn];

int n,m,k;
int cnt;

void SS(int x, int y) {
  a[x][y] = '*';
  cnt++;
  for(int i = 0; i < 4; i++) {
    int xx = x + dx[i];
    int yy = y + dy[i];
    if(xx >= 1 && xx <= n && yy >= 1 && yy <= m)
      if(a[xx][yy] == '.')
        SS(xx, yy);
  }
}

struct aa {
  int x,y;
  int v;
}h[kMaxn * kMaxn];

bool cmp(aa p, aa q) {
  return p.v < q.v;
}

int main() {
  scanf("%d %d %d", &n, &m, &k);
  for(int i = 1; i <= n; i++) {
    getchar();
    for(int j = 1; j <= m; j++) {
      scanf("%c", &a[i][j]);
      b[i][j] = a[i][j];
    }
  }
  for(int j = 1; j <= m; j++) {
    SS(0, j);
    SS(n + 1, j);
  }
  for(int i = 1; i <= n; i++) {
    SS(i, 0);
    SS(i, m + 1);
  }
  /*for(int i = 1; i <= n; i++) {
    for(int j = 1; j <= n; j++)
      printf("%c", a[i][j]);
    printf("\n");
  }*/
  int l = 0;
  for(int i = 1; i <= n; i++) {
    for(int j = 1; j <= m; j++) {
      if(a[i][j] == '.') {
        cnt = 0;
        SS(i, j);
        l++;
        h[l].v = cnt;
        h[l].x = i; h[l].y = j;
      }
    }
  }
  sort(h + 1, h + 1 + l, cmp);
  for(int i = 1; i <= n; i++) 
    for(int j = 1; j <= m; j++)
      a[i][j] = b[i][j];
  int sum = 0;
  for(int i = 1; i <= l - k; i++) {
    sum += h[i].v;
    SS(h[i].x, h[i].y);
  }
  printf("%d\n", sum);
  for(int i = 1; i <= n; i++) {
    for(int j = 1; j <= m; j++)
      printf("%c", a[i][j]);
    printf("\n");
  }
  return 0;
}

E. One-Way Reform

题意

这题就有点难度了。。比赛的时候没做出来,赛后题解都看了半天。。。。
大致意思是说有一个无向图,现在要改成有向图了,问用哪些边可以让出度等于入度的点最多。

思路

有向图欧拉图出度等于入度。。那么也就说度数为偶数的点都可以。。。
先把这个图转成欧拉图。。。把度数为奇数的点取出来,然后连虚拟边。。。跑欧拉图把边输出就行了,当然虚拟边不要输出了。。

代码

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

typedef pair<int,int>PI;

const int kMaxn = 200 + 5;

struct Edge {
  int from,to,next;
  bool flag;
} e[kMaxn * kMaxn];

int head[kMaxn], degree[kMaxn];
int top,ed;

vector<int>a;
vector<PI>g;

void Init() {
  top = 0;
  memset(head, -1, sizeof(head));
  memset(degree, 0, sizeof(degree));
  g.clear();
  a.clear();
}

void AddEdge(int from, int to) {
  e[top].from = from;
  e[top].to = to;
  e[top].next = head[from];
  e[top].flag = false;
  head[from] = top++;
} 

void Dfs(int u) {
  for(int i = head[u]; i != -1; i = e[i].next) {
    if(!e[i].flag) {
      e[i].flag = true;
      e[i ^ 1].flag = true; //无向图两个方向都标记上
      if(i <= ed) //不是虚拟边的才存起来
        g.push_back(make_pair(e[i].from, e[i].to));
      Dfs(e[i].to);
    }
  }
}

int main() {
  int t;
  scanf("%d", &t);
  while(t--) {
    Init();
    int n,m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= m; i++) {
      int u,v;
      scanf("%d %d", &u, &v);
      AddEdge(u,v); AddEdge(v,u);
      degree[u]++; degree[v]++;
    }
    ed = top - 1; //到这里为止的边都是本来就有的,后面的边就是自己加的了
    int ans = 0;
    for(int i = 1; i <= n; i++) {
      if(degree[i] % 2 == 0)
        ans++;
      else a.push_back(i);
    }
    for(int i = 0; i < a.size(); i = i + 2)  {
      AddEdge(a[i], a[i + 1]);
      AddEdge(a[i + 1], a[i]);
    }
    for(int i = 0; i < top; i++)
      if(!e[i].flag)
        Dfs(e[i].from);
    printf("%d\n", ans);
    for(int i = 0; i < g.size(); i++)
      printf("%d %d\n", g[i].first, g[i].second);
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值