A、B水题,C、D应该算是思维题,A题做的有点慢,不然应该有时间推一下C题
- A. Paint the Numbers
题意:给一串序列,给序列中数染色,公因数相同的可以染同一颜色,求最少需要染的颜色
思路:首先排序,对一个数和所有序列中存在的其倍数染同一颜色,求出最终颜色数即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
int n, a[maxn], b[maxn];
int main()
{
cin >> n;
set<int> s;
int ans = 0, maxx = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
b[i] = 0;
maxx = max(a[i], maxx);
s.insert(a[i]);
}
sort(a, a+n);
for (int i = 0; i < n; i++) {
if (!b[a[i]])
ans++;
for (int j = a[i]; j <= maxx; j+=a[i]) {
if (s.count(j)) {
b[j] = ans;
}
}
}
cout << ans << "\n";
return 0;
}
- B. Koala and Lights
题意:给一串灯,1表示亮,0表示灭,每盏灯会重复点亮、熄灭,给出每盏灯开始重复的时间和重复周期,求出某个时间里点亮的最多灯数
思路:数据比较小(100),可以模拟个10000时间周期,求出最大点亮灯数即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
int n, a[maxn], b[maxn], sta[maxn], temp[maxn];
int main()
{
cin >> n;
int ans = 0, t = 0;
string s;
cin >> s;
for (int i = 0; i < n; i++) {
if (s[i] == '1') {
sta[i] = 1;
ans++;
}
else
sta[i] = 0;
}
for (int i = 0; i < n; i++)
cin >> a[i] >> b[i];
memcpy(temp, sta, sizeof(sta));
for (int j = 1; j < 10000; j++) {
int cnt = 0;
for (int i = 0; i < n; i++) {
if (b[i] == j || (j-b[i] > 0 && (j-b[i]) % a[i] == 0))
temp[i] = !temp[i];
if (temp[i])
cnt++;
}
ans = max(ans, cnt);
}
cout << ans << "\n";
return 0;
}
- C. Paint the Digits
题意:给一串序列,可以给数字染色1或者2,要求染色过后连续的1要在连续的2之前,且这样排列的串为递增序列
思路:首先将原序列排序放到另一数组里,和原序列对比,遍历两次,第一次染1,第二次染2,若这样过后还有元素没染色,则不存在答案,否则当前染色方案即为答案
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
int n, T, c[maxn], b[maxn];
struct node {
int index, val;
node(int index = 0, int val = 0) : index(index), val(val) {
}
}a[maxn];
bool cmp(node x, node y)
{
return x.val < y.val;
}
int main()
{
cin >> T;
string s;
for (int t = 0; t < T; t++) {
cin >> n >> s;
for (int i = 0; i < n; i++) {
a[i] = node(i, s[i]-'0');
b[i] = s[i]-'0';
}
sort(a, a+n, cmp);
memset(c, 0, sizeof(c));
int cur = 0;
for (int i = 0; i < n; i++) {
if (a[cur].val == b[i]) {
c[i] = 1;
cur++;
}
}
for (int i = 0; i < n; i++) {
if (a[cur].val == b[i] && !c[i]) {
c[i] = 2;
cur++;
}
}
if (cur != n) {
cout << "-\n";
continue;
}
else {
for (int i = 0; i < n; i++)
cout << c[i];
cout << "\n";
}
}
return 0;
}
- D. Cow and Snacks
题意:给k个奶牛,n个零食,每个奶牛有2个偏好零食,轮到某个奶牛时,它会将所有偏好零食吃完。要求对奶牛安排某一队列,使得没有零食可选的奶牛数最少,求出这样的奶牛个数
思路:可以将零食作为节点,奶牛作为边,显然两个点之间最多存在一条边,否则就会有奶牛没零食可选。用并查集将每个奶牛偏爱零食放到一个集合里,若某个奶牛两个偏爱零食已在同一集合,则其无零食可选
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int n, k, u[maxn];
int ufind(int x)
{
if (u[x] != x)
u[x] = ufind(u[x]);
return u[x];
}
void unite(int x, int y)
{
u[ufind(x)] = ufind(y);
}
int main()
{
// freopen("test.txt", "r", stdin);
cin >> n >> k;
for (int i = 1; i <= n; i++)
u[i] = i;
int ans = 0;
for (int i = 0; i < k; i++) {
int x, y;
cin >> x >> y;
if (ufind(x) != ufind(y))
unite(x, y);
else
ans++;
}
cout << ans << "\n";
return 0;
}
- G1. Into Blocks (easy version)
题意:给一个序列n个数字,可以把某个数字和序列中所有等于它的位置的数字变为另一数字,为了使所有相等的数字都相邻,求出需要更改的数字总个数
思路:一直以为后面的题都是复杂的算法题,结果这道是道简单题,认真推一下就可以得出答案,赛后直接一发AC了。实际上这道题就是求区间的并集,相同数字的最远距离构成一个区间,比如3 3 1 3 2 1 2
的并集就是整个序列,若某两个区间存在交集,就需要更改数字,修改个数等于区间内不同数字中数量较少数字个数,从前往后存储区间位置,就可以保证答案是正确的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
const int inf = 0x3f3f3f3f;
int n, q, id[maxn], cnt = 0;
vector<vector<int> > m(maxn);
int main()
{
cin >> n >> q;
memset(id, 0, sizeof(id));
for (int i = 1; i <= n; i++) {
int k;
cin >> k;
if (!id[k])
id[k] = ++cnt;
m[id[k]].push_back(i);
}
int maxlen = 0, r = 1, ans = 0;
for (int i = 1; i <= cnt; i++) {
int len = m[i].size();
if (m[i][0] < r) {
if (maxlen > len) {
ans += len;
} else {
ans += maxlen;
maxlen = len;
}
} else {
maxlen = 0;
}
if (m[i][len-1] > r) {
r = m[i][len-1];
maxlen = max(maxlen, len);
}
}
cout << ans << "\n";
return 0;
}