概述
这场的题其实都挺水。。。但是还是只做了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;
}