A. The New Year: Meeting Friends
同一直线上的三个人要集合,求三个人一共走的距离的最小值。
max(a, b, c) - min(a, b, c)
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 5e4 + 50;
const int MAXM = 1e4 + 50;
int a, b, c;
int main() {
#ifdef LOCAL_NORTH
// FIN;
#endif // LOCAL_NORTH
while (~scanf("%d%d%d", &a, &b, &c)) {
printf("%d\n", max(a, max(b, c)) - min(a, min(b, c)));
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
B. Text Document Analysis
输出括号外的单词的最大长度已经括号内单词的个数。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 5e4 + 50;
const int MAXM = 1e4 + 50;
int n;
string s;
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (cin >> n >> s) {
int ans1 = 0, ans2 = 0, len = 0, in = 0;
for (int i = 0; i < n; i++) {
if (isalpha(s[i])) len++;
else {
if (!in) ans1 = max(ans1, len);
else if (len) ans2++;
len = 0;
if (s[i] == '(' || s[i] == ')') in = 1 - in;
}
}
ans1 = max(ans1, len);
printf("%d %d\n", ans1, ans2);
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
C. Polycarp at the Radio
有n首曲子明天要演奏,一个人希望他喜欢的m个乐队演奏的歌曲数的最大值最小。输出改变次数最少的演奏安排。
目的是使m个乐队至少演奏n/m首。
统计一下原来这m个乐队演奏的数目并排序。目的是使原本歌曲数多的演奏n/m+1首或n/m首(根据原本的次数判断一下改变后按演奏多少),原本少的演奏n/m首。这样一来,改变的次数就必定最小。
计算出为符合要求,乐队i需要增加或减少的歌曲数op[i]。这时op数组有正有负,来一次n^2的操作把所有的负数消掉,即找到op[i] < 0,op[j] > 0,然后op[i]++,op[j]--。
最后遍历整个序列,把大于m的乐队变为小于等于m的乐队。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 2e3 + 50;
const int MAXM = 1e4 + 50;
int m, n, a[MAXN], op[MAXN], c[MAXN];
struct node{
int c, id;
node(int _c, int _id) {c = _c; id = _id;}
bool operator < (const node& _) const {return c > _.c;}
};
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (~scanf("%d%d", &n, &m)) {
memset(c, 0, sizeof(c));
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i] >= 1 && a[i] <= m) c[a[i]]++;
}
vector<node> v;
for (int i = 1; i <= m; i++) v.pb(node(c[i], i));
sort(v.begin(), v.end());
int ans1 = n / m, ans2 = 0;
// for (int i = 0; i < m; i++) printf("[%d]%c", v[i].c, " \n"[i == m - 1]);
int fck = n % m;
for (int i = 0; i < m; i++) {
int id = v[i].id;
op[id] = n / m - c[id];
while (fck && op[id] <= -1) {
op[id]++;
fck--;
}
ans2 += abs(op[id]);
}
// for (int i = 1; i <= m; i++) printf("%d%c", op[i], " \n"[i == m]);
for (int i = 1; i <= m; i++) {
while (op[i] < 0) {
int s = -1;
for (int j = 1; j <= m; j++) {
if (op[j] > 0) {
s = j;
break;
}
}
for (int j = 1; j <= n; j++) {
if (a[j] == i) {
a[j] = s;
op[i]++;
op[s]--;
ans2--;
break;
}
}
}
}
printf("%d %d\n", ans1, ans2);
for (int i = 1; i <= n; i++) {
if (a[i] < 1 || a[i] > m) {
for (int j = 1; j <= m; j++) {
if (op[j] > 0) {
op[j]--;
a[i] = j;
break;
}
}
}
printf("%d%c", a[i], " \n"[i == n]);
}
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
D. Lakes in Berland
把最少的水地变为土地,使得湖(连通块)的数目等于k。
bfs一遍统计出湖的个数、每个湖的大小以及湖的任意一点。
排序后,从每个湖中的点开始,把前tot-k个湖变为土地。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 100 + 50;
const int MAXM = 1e4 + 50;
int n, m, k, d[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
char p[MAXN][MAXN];
bool vis[MAXN][MAXN];
struct node{
int x, y, c;
bool operator < (const node& _) const {return c < _.c;}
}lakes[MAXN * MAXN];
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (~scanf("%d%d%d", &n, &m, &k)) {
memset(vis, false, sizeof(vis));
for (int i = 1; i <= n; i++) scanf("%s", p[i] + 1);
int tot = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (p[i][j] == '.' && !vis[i][j]) {
bool ok = true;
int cnt = 0;
queue<PII > q;
q.push(mp(i, j));
vis[i][j] = true;
while (!q.empty()) {
PII cur = q.front();
q.pop();
int x = cur.first, y = cur.second;
cnt++;
if (x < 1 || x > n || y < 1 || y > m) {
ok = false;
continue;
}
for (int l = 0; l < 4; l++) {
int xx = x + d[l][0], yy = y + d[l][1];
if (xx >= 0 && xx <= n + 1 && yy >= 0 && yy <= m + 1 && !vis[xx][yy] && p[xx][yy] != '*')
q.push(mp(xx, yy));
vis[xx][yy] = true;
}
}
if (ok) {
lakes[tot].c = cnt;
lakes[tot].x = i;
lakes[tot++].y = j;
}
}
}
}
sort(lakes, lakes + tot);
int ans = 0;
for (int i = 0; i < tot - k; i++) {
ans += lakes[i].c;
queue<PII > q;
q.push(mp(lakes[i].x, lakes[i].y));
p[lakes[i].x][lakes[i].y] = '*';
while (!q.empty()) {
PII cur = q.front();
q.pop();
int x = cur.first, y = cur.second;
for (int j = 0; j < 4; j++) {
int xx = x + d[j][0], yy = y + d[j][1];
if (xx > 0 && xx <= n && yy > 0 && yy <= m && p[xx][yy] != '*') {
p[xx][yy] = '*';
q.push(mp(xx, yy));
}
}
}
}
printf("%d\n", ans);
for (int i = 1; i <= n; i++) printf("%s\n", p[i] + 1);
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
E. One-Way Reform
把无向图转化为有向图,同时使得出度等于入度的点最多。并打印边。
为了使出度等于入度的点最多,要把原图转化为欧拉图,操作为:原图中奇数度的点一定有偶数个,所有将度为奇数的点两两(不是点i与所有的奇数度点连边,而是点i与任意一奇数度点相连)之间加一条边。
然后用Fleury打印欧拉回路即可,注意添加的边不要打印。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 50;
const int MAXM = 1e5 + 50;
int n, m, d[MAXN];
bool vis[MAXN];
struct Edge{
int v, f, p, nxt;
} E[MAXM << 1];
int tot, Head[MAXN];
void edge_init() {
tot = 0;
memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int p) {
E[tot].v = v; E[tot].f = 0; E[tot].p = p; E[tot].nxt = Head[u]; Head[u] = tot++;
E[tot].v = u; E[tot].f = 0; E[tot].p = p; E[tot].nxt = Head[v]; Head[v] = tot++;
}
vector<int> odd;
void dfs(int u) {
vis[u] = true;
for (int i = Head[u]; ~i; i = E[i].nxt) {
if (E[i | 1].f) continue;
E[i | 1].f = 1;
if (E[i].p) printf("%d %d\n", u, E[i].v);
dfs(E[i].v);
// return; !!!!
}
}
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
int T;
scanf("%d", &T);
while (T--) {
memset(d, 0, sizeof(d));
memset(vis, false, sizeof(vis));
odd.clear();
edge_init();
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d%d", &u, &v);
edge_add(u, v, 1);
d[u]++;
d[v]++;
}
int ans = 0;
for (int i = 1; i <= n; i++)
if (d[i] & 1) odd.pb(i);
else ans++;
for (int i = 0, sz = odd.size(); i < sz - 1; i += 2)
edge_add(odd[i], odd[i + 1], 0);
printf("%d\n", ans);
for (int i = 1; i <= n; i++)
if (!vis[i])
dfs(i);
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}
F. st-Spanning Tree
在原图的基础上构建一棵生成树,同时s的度不大于ds,t的度不大于dt,并打印边。
为了使和s、t相连的边数最少,需要在去掉s和t的每个连通分量内构建一棵生成树。
然后把所有生成树连到s和t上。需要注意不是随便连,否则会出现一个连通分量既可以连到s,也可以连到t,但最后连错导致s和t度数错误。一种可行的方法是每次遇到上文描述的情况,将生成树连到距离度数限制较大的点上。
经过上一步,原图已经变成了两棵生成树,同时注意到图中没有被选中用来构建生成树的边只有3种:
1)端点为s和t;2)一端为s,另一端不为t;3)一端为t,另一端不为s。
现在只需要在一棵生成树上找到任意一条连上后符合题意的边。
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 2e5 + 50;
const int MAXM = 4e5 + 50;
int n, m, s, t, ds, dt;
struct Edge{
int u, v;
}E[MAXM];
int par[MAXN];
int Find(int x) {return par[x] == x ? x : par[x] = Find(par[x]);}
void unite(int a, int b) {
int x = Find(a), y = Find(b);
if (x != y) par[x] = y;
}
vector<PII > ans;
bool link[MAXN][2];
int STlink[MAXN], dus, dut;
bool ST2S[MAXN], ST2T[MAXN];
void solveST() {
for (int i = 0; i < m; i++) {
int u = E[i].u, v = E[i].v;
if (u == s || u == t || v == s || v == t)
continue;
if (Find(u) != Find(v)) {
unite(u, v);
ans.pb(mp(u, v));
}
}
memset(ST2S, false, sizeof(ST2S));
memset(ST2T, false, sizeof(ST2T));
for (int i = 1; i <= n; i++) {
if (i == s || i == t) continue;
if (link[i][0])
ST2S[Find(i)] = true;
if (link[i][1])
ST2T[Find(i)] = true;
}
}
void linkST() {
dus = dut = 0;
memset(STlink, -1, sizeof(STlink));
for (int i = 1; i <= n; i++) {
if (i == s || i == t) continue;
int stNo = Find(i);
if (STlink[stNo] != -1) continue;
bool ok1 = (ST2S[stNo] && dus < ds && link[i][0]);
bool ok2 = (ST2T[stNo] && dut < dt && link[i][1]);
int tmp = -1;
if (ok1 && ok2) {
if (ds - dus > dt - dut) tmp = s;
else tmp = t;
} else if (ok1) tmp = s;
else if (ok2) tmp = t;
if (tmp == s) {
STlink[stNo] = 0;
unite(i, s);
ans.pb(mp(i, s));
dus++;
} else if (tmp == t) {
STlink[stNo] = 1;
unite(i, t);
ans.pb(mp(i, t));
dut++;
}
}
}
bool Link() {
if (dus < ds && dut < dt && link[t][0]) {
dut++, dus++;
ans.pb(mp(s, t));
unite(s, t);
return true;
}
for (int i = 1; i <= n; i++) {
if (i == s || i == t) continue;
if (Find(i) == Find(s)) {
if (dut < dt && link[i][1]) {
dut++;
ans.pb(mp(t, i));
unite(i, t);
return true;
}
} else if (Find(i) == Find(t)) {
if (dus < ds && link[i][0]) {
dus++;
ans.pb(mp(s, i));
unite(i, s);
return true;
}
}
}
return false;
}
int main() {
#ifdef LOCAL_NORTH
FIN;
#endif // LOCAL_NORTH
while (~scanf("%d%d", &n, &m)) {
ans.clear();
memset(link, false, sizeof(link)); //link[i][0]表示是i否与s相连,link[i][1]表示i是否与t相连。
for (int i = 1; i <= n; i++) par[i] = i;
for (int i = 0; i < m; i++)
scanf("%d%d", &E[i].u, &E[i].v);
scanf("%d%d%d%d", &s, &t, &ds, &dt);
for (int i = 0; i < m; i++) {
if (E[i].u == s || E[i].v == s)
link[E[i].u + E[i].v - s][0] = true;
if (E[i].u == t || E[i].v == t)
link[E[i].u + E[i].v - t][1] = true;
}
link[s][0] = link[t][1] = true;
solveST(); //构建生成树
linkST(); //生成树连向s和t
if (dus > ds || dut > dt) {
printf("No\n");
continue;
}
bool ok = Link(); //两棵生成树相连
for (int i = 1; i <= n; i++)
ok &= (Find(i) == Find(1));
if (!ok) {
printf("No\n");
continue;
}
if (dus <= ds && dut <= dt) {
printf("Yes\n");
int sz = ans.size();
for (int i = 0; i < sz; i++)
printf("%d %d\n", ans[i].first, ans[i].second);
} else printf("No\n");
}
#ifdef LOCAL_NORTH
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
return 0;
}