http://codeforces.com/contest/1209

B. Koala and Lights

 

题意:n个灯,从第b[i]秒开始变,周期为a[i],问最多有几个灯同时亮。

数字不大,直接枚举时间,周期很小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int n;
int a[N], b[N], c[110][1010];
char s[N];
int main() {
scanf("%d", &n);
scanf("%s", s + 1);
for (int i = 1; i <= n; i++)scanf("%d%d", &a[i], &b[i]);
int ans = 0;
for (int t = 0; t < 1000; t++) {
int tmp = 0;
for (int i = 1; i <= n; i++) {
if (t < b[i])tmp += (s[i] - '0'), c[i][t] = (s[i] - '0');
else {
c[i][t] = c[i][max(0, t - a[i])] ^ 1;
tmp += c[i][t];
}
}
ans = max(ans, tmp);
}
printf("%d\n", ans);
return 0;
}

 

C. Paint the Digits

 

题意:给定一串数字,要求分成两个序列,再拼起来后非递减。

单调栈

一个数字前面如果有比它大的数字,那么这两个数字一定不能在一个序列里,且大的那个一定在第二个序列,小的那个一定在第一个序列。

单调栈维护非递减序列,作为第一个序列,同时要保证单调栈里的数不大于第二个序列的最小值,这样保证了第一个序列不能再加了,再判断第二个序列是否合法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int T;
int n;
char s[N];
typedef pair<int, int>pii;
pii S[N]; int top, c[N];
vector<pii>vc;
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
scanf("%s", s + 1);
top = 0; vc.clear();
int mn = INF;
for (int i = 1; i <= n; i++) {
if (s[i] - '0' > mn) {
vc.push_back(pii(s[i] - '0', i));
mn = min(mn, s[i] - '0');
continue;
}
while (top&&S[top].first > (s[i] - '0'))
vc.push_back(S[top]), mn = min(mn, S[top--].first);
S[++top] = pii(s[i] - '0', i);
}
bool ok = 1;
fill(c + 1, c + n + 1, 1);
sort(vc.begin(), vc.end());
for (int i = 0; i < (int)vc.size(); i++) {
if (i > 0 && vc[i].second < vc[i - 1].second) { ok = 0; break; }
c[vc[i].second] = 2;
}
if (!ok)puts("-");
else {
for (int i = 1; i <= n; i++)printf("%d", c[i]);
puts("");
}
}
return 0;
}

 

D. Cow and Snacks

 

题意:n个人,每人有两个要的食物,每种食物只有一个,每个人会贪心地拿走他要的两种食物,问怎么安排顺序使得一个食物都没有的人数最少。

最大流啊,但是复杂度不够。

生成树

把食物作为点,一个人连接两个点,不同连通分量之间无关,对于一个连通分量,可以构造出最优顺序,使得有东西吃的人数为点数-1:先随便挑一条边,吃两个,再bfs出去,每次吃一个,由于每个点只能被吃一次,所以这一定是最优解。

也就是连通分量的生成树边数,那么没东西吃的人数就是连通分量里非树边的边数,并查集维护即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int par[N];
void init(int n) { for (int i = 0; i <= n; i++)par[i] = i; }
int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); }
void uni(int x, int y) { par[find(x)] = find(y); }
int n, m, ans;
int main() {
scanf("%d%d", &n, &m);
init(n);
while (m--) {
int u, v;
scanf("%d%d", &u, &v);
if (find(u) == find(v))ans++;
else uni(u, v);
}
printf("%d\n", ans);
return 0;
}