第十七届中国计量大学程序设计竞赛部分题解

比赛链接:第十七届中国计量大学程序设计竞赛



B - Broken Pad

两种情况:

  • 原字符串从左往右翻转;
  • 先单击空白处,再从左往右翻转。

结果取两者中次数较少的。

#include <iostream>
#include <string>
#include <queue>
using namespace std;
#define io_speed_up ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

string a, b;
int t, cnt1, cnt2, cnt, len;
queue <int> q1, q2;

int main() {
	io_speed_up;
	cin >> t;
	while (t--) {
		cin >> a >> b;
		while (!q1.empty())	q1.pop();
		while (!q2.empty())	q2.pop();
		cnt1 = cnt = 0, len = a.length();
		for (int i = 0; i < len; ++i) {
			int t1 = a[i] - '0', t2 = b[i] - '0';
			if (cnt && t1 ^ 1 != t2) {
				q1.push(i + 1);
				cnt ^= 1;
				cnt1++;
			} else if (!cnt && t1 != t2) {
				q1.push(i + 1);
				cnt ^= 1;
				cnt1++;
			}
		}
		cnt2 = 1, cnt = 0;
		q2.push(0);
		for (int i = 0; i < len; ++i) {
			int t2 = b[i] - '0';
			if (cnt && !t2) {
				q2.push(i + 1);
				cnt ^= 1;
				cnt2++;
			} else if (!cnt && t2) {
				q2.push(i + 1);
				cnt ^= 1;
				cnt2++;
			}
		}
		if (cnt1 <= cnt2) {
			while (!q1.empty()) {
				cout << q1.front() << ' ';
				q1.pop();
			}
		} else {
			while (!q2.empty()) {
				cout << q2.front() << ' ';
				q2.pop();	
			}
		}
		cout << endl;
	}
	return 0;
}

C - Cook Steak

一道简单的模拟题,按顺序计算时间即可。

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

int t, n;

int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        vector <pair<int, int> > vec;
        for (int i = 1; i <= n; ++i) {
            int l, r;
            cin >> l >> r;
            vec.push_back(make_pair(l, r));
        }
        int now = 0, p = 0;
        ll time = 0;
        while (p < n) {
            int v = 1;
            if (now < vec[p].first) {
                v = vec[p].first - now;
                now = vec[p].first;
            }
            else if (now > vec[p].second) {
                v = now - vec[p].second;
                now = vec[p].second;
            }
            else { 
                p++; 
            }
            time += v;
        }
        cout << time << endl;
    }
    return 0;
}

D - Dessert Time

首先我们将出现的数字排序,统计出现次数,这里选用map存储。
可以分类成以下三种情况:

  1. 从大到小看,第一个出现奇数次的数是最小的数:
    如果我们第一步拿最小的数,那么之后对手只需要按顺序拿即可让我们拿最后一个数;如果我们第一步拿其他数,那么对手只需模仿我们的操作,直到拿掉最后一个数让我们兜底;因此,这是必败态;
  2. 从大到小看,第一个出现奇数次的数不是最小的数:
    此时我们只要第一步拿这个奇数次的数就是必胜,当我们拿了该数以后,它及它之后的数字全都是偶数次,我们只需要模仿对手的操作即可拿到最后一个数使对手兜底;
  3. 所有数都是偶数次:
    此时我们先手取最小的数必胜,若对手模仿我们的操作,他会拿到最后一个数,若他不模仿我们的操作而先拿一个较大的数,那么我们模仿他的操作,就能拿到最后一个数使对手兜底。
#include <iostream>
#include <map>
using namespace std;

int t, n, x, ans;
map <int, int> mat;

int main() {
	cin >> t;
	while (t--) {
		mat.clear();
		cin >> n;
		for (int i = 1; i <= n; ++i) {
			cin >> x;
			mat[x]++;
		}
		ans = -1;
		for (auto iter = (--mat.end()); ; --iter) {
			if (iter->second & 1) {
				ans = iter->first;
				break;
			}
			if (iter == mat.begin()) {
				break;
			}
		}
		if (ans == -1) {
			ans = mat.begin()->first;
		} else if (ans == mat.begin()->first) {
			ans = -1;
		}
		cout << ans << endl;
	}
	return 0;
}

E - Eat Grapes

首先考虑一般情况:
当一个节点连接大于1个葡萄时,先手的人总能通过策略留最后1个葡萄给对手,所以这题变成在求当遇到第一个拥有大于1个葡萄的节点时谁是先手;
当一个节点没有连接葡萄时,它只拥有上一个节点这1个葡萄,所以我们只要知道最后连续有多少个节点没有连接葡萄,就可以知道之后谁先手;
由于最后一个节点总留有一个额外的葡萄,所以偶数个连续的节点代表SYH赢。
特殊情况:
如果所有节点都没有连接葡萄,那么结果与上面的情况相反。

#include <iostream>
using namespace std;

int t, n, num, cnt;

int main() {
	cin >> t;
	while (t--) {
		cin >> n;
		cnt = 0;
		for (int i = 1; i <= n; ++i) {
			cin >> num;
			if (num) {
				cnt = 0;
			} else {
				cnt++;
			}		
		}
		if (cnt == n) {
			if (cnt % 2) {
				cout << "these are sweet grapes" << endl;
			} else {
				cout << "these are sour grapes" << endl;
			}
		} else if (cnt % 2) {
			cout << "these are sour grapes" << endl;
		} else {
			cout << "these are sweet grapes" << endl;
		}
	}
	return 0;
}

F - Flag Scramble Competition

签到题,数都能数出来。

#include <cstdio>
using namespace std;
 
int main() {
    printf("e");
    return 0;
}

H - Happy Time is Always Short

线段树的模板题,把求和改成取最大值即可。

#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))

struct node {
	ll tree, left, right, lazy;
} a[400050];

ll t, n, m, add, ans, x, y;

ll read() {
	char x = getchar(); ll ans = 0; int f = 1;
	while (!isdigit(x)) {
		if (x == '-')   f = -1;
		x = getchar();
	}
	while (isdigit(x)) {
		ans = (ans << 3) + (ans << 1) + (x ^ 48);
		x = getchar();
	}
	return ans * f;
}

void create(ll l, ll r, ll k) {
	a[k].lazy = 0, a[k].left = l, a[k].right = r;
	if (l == r) {
		a[k].tree = read();
		return;
	}
	ll mid = l + r >> 1;
	create(l, mid, k * 2);
	create(mid + 1, r, k * 2 + 1);
	a[k].tree = max(a[k * 2].tree, a[k * 2 + 1].tree);
	return;
}

void load(ll k) {
	ll l = k * 2, r = k * 2 + 1;
	a[l].lazy = 1;
	a[r].lazy = 1;
	a[l].tree = 0;
	a[r].tree = 0;
	a[k].lazy = 0;
	return;
}

void change(ll k) {
	if (a[k].left >= x && a[k].right <= y) {
		a[k].tree = 0;
		a[k].lazy = 1;
		return;
	}
	if (a[k].lazy)      load(k);
	ll mid = a[k].left + a[k].right >> 1;
	if (x <= mid)       change(k * 2);
	if (y >= mid + 1)   change(k * 2 + 1);
	a[k].tree = max(a[k * 2].tree, a[k * 2 + 1].tree);
	return;
}

void inquery(ll k) {
	if (a[k].left >= x && a[k].right <= y) {
		ans = max(ans, a[k].tree);
		return;
	}
	if (a[k].lazy)      load(k);
	ll mid = a[k].left + a[k].right >> 1;
	if (x <= mid)       inquery(k * 2);
	if (y >= mid + 1)   inquery(k * 2 + 1);
	return;
}

int main() {
	t = read();
	while (t--) {
		ms(a, 0);
		n = read();
		m = read();
		create(1, n, 1);
		while (m--) {
			x = read(), y = read();
			ans = 0;
			change(1);
			x = 1, y = n;
			inquery(1);
			printf("%lld\n", ans);
		}
	}
	return 0;
}

I - Isolated Pointset

根据说明就能看出来,只要大于等于三个点,就可以一直拼成一排等边三角形。

#include <iostream>
using namespace std;

int t, num;

int main() {
	cin >> t;
	while (t--) {
		cin >> num;
		if (num > 2) {
			cout << "Yes" << endl;
		} else {
			cout << "No" << endl;
		}
	}
	return 0;
}

J - Jiufeng's Football Team

用种类并查集来区分两个团队,在球员之间建边,边权为训练时间。
给定一个时间,大于该时间的边所属的两个球员放在不同团队;当所有球员都分配完毕时,没有出现矛盾的情况,则该时间满足条件;若出现两个球员的训练时间大于给定时间,但根据之前球员的分配,这两个球员在同一团队,则产生矛盾,该时间不满足条件。
通过二分的方法来获取训练时间的最小值。

#include <iostream>
#include <vector>
using namespace std;
#define ll long long
#define MAXN 400010

int t, n, m, fa[MAXN], x, y, w;
struct Edge {
	int to, w;
};
vector <Edge> edge[MAXN];

int find(int x) {
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}

bool check(int x) {
	for (int i = 1; i <= 2 * n; ++i)	fa[i] = i;
	for (int i = 1; i <= n; ++i) {
		for (auto iter : edge[i]) {
			if (iter.w <= x)	continue;
			int nxt = iter.to;
			int x = find(i);
			int y = find(nxt);
			if (x == y)	return false; // 在同一个团队
			fa[find(x + n)] = find(y);
			fa[find(y + n)] = find(x);
		}
	}
	return true;
}

int main() {
	cin >> t;
	while (t--) {
		cin >> n >> m;
		for (int i = 1; i <= n; ++i)	edge[i].clear();
		for (int i = 1; i <= m; ++i) {
			cin >> x >> y >> w;
			edge[x].push_back(Edge{y, w});
			edge[y].push_back(Edge{x, w});
		}
		int l = 0, r = 1e9, ans = r;
		while (l <= r) {
			int mid = l + r >> 1;
			if (check(mid)) {
				r = mid - 1;
				ans = mid;
			} else {
				l = mid + 1;
			}
		}
		cout << ans << endl;
	}
	return 0;
}

K - Known-Well Palindrome Date-Easy Version

按顺序从左往右判断:

  1. 先用string类的substr函数每次截取八个字符;
  2. 用algorithm头文件里的reverse函数翻转截取的字符串,并与原字符串判断回文;
  3. 判断八个字符中是否存在空格;
  4. 判断日期的合理性。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int n, len;
string s;

bool judge(int year) {
    return (!(year % 400) || year % 100 && !(year % 4));
}

int main() {
    while (getline(cin, s)) {
        if (s == "#")   break;
        n = 0;
        len = s.length();
        for (int i = 0; i <= len - 8; ++i) {
            // 判断回文 
            string s1 = s.substr(i, 8);
            string s2 = s1;
            reverse(s1.begin(), s1.end());
            if (s1 == s2) {
                // 去除空格 
                bool flag = false;
                for (int j = i; j <= i + 7; ++j) {
                    if (s[j] > '9' || s[j] < '0') {
                        flag = true;
                        break;  
                    }
                }
                if (flag)   continue;
                // 判断日期合理性 
                int yy = (((s[i] - '0') * 10 + s[i + 1] - '0') * 10 + s[i + 2] - '0') * 10 + s[i + 3] - '0';
                int mm = (s[i + 4] - '0') * 10 + s[i + 5] - '0';
                int dd = (s[i + 6] - '0') * 10 + s[i + 7] - '0';
                if (mm == 1 || mm == 3 || mm == 5 || mm == 7 || mm == 8 || mm == 10 || mm == 12) {
                    if (dd <= 31 && dd > 0) {
                        n++;
                    }
                } else if (mm == 4 || mm == 6 || mm == 9 || mm == 11) {
                    if (dd <= 30 && dd > 0) {
                        n++;
                    }
                } else if (mm == 2) {
                    if (judge(yy)) {
                        if (dd <= 29 && dd > 0) {
                            n++;
                        }
                    } else {
                        if (dd <= 28 && dd > 0) {
                            n++;
                        }
                    }
                }
            }
        }
        cout << n << endl;
    }
    return 0;
}
posted @ 2020-09-26 18:33  ZZHHOOUU  阅读(187)  评论(0编辑  收藏  举报