省选测试 11
T1
题目链接
排序 + 贪心.
我们将(a)从大到小排序后可以得到 : (a_1 geq a_2 geq dots geq a_n).
所以我们可以知道 : (|a_2 - a_3| + |a_4 - a_5| + dots + |a_{n-1} - a_n| < a_1).(因为(a_i geq 1))
这个条件有什么用呢? 我们为了时选出的(a)合法, 那么就要(suma(选) > suma(未选)).
我们要选出(frac{n}{2} +1)个数, 我们考虑这么选 : 一定选(a_1), 其余的(a_2, a_3)选一个, (a_4,a_5)选一个 ...为什么这么选呢? 由上面那个条件可以知道, 这么选一定是 (suma(选) > suma(未选)) 的.
所以我们贪心的在每个块里选(b_i)较大的就好了.
但是还有个问题, 万一只有选两个相邻的(b)才能满足条件怎么办? 其实这种情况不会发生, 下面是证明 :
比如说有 : (b_1, b_2, b_3, b_4, b_5).
只有 : (2*(b_1 +b_2 +b_3) > sumb), 没有 : (2*(b_1 + b_{2 | 3} +b_{4|5}) <= sumb)
那么我们可以得到 : (b_1 + b_2 + b_3 > b_4 + b_5), (b_1 +b_2 + b_4 <= b_3 + b_5(2))
既然我们按上面的方法选出了(b_1, b_2, b_4), 那么就说明 : (b_2 >= b_3, b_4 >= b_5)
又由上面的((2))式移项可以得到 : (b_1 <= b_3 - b_2 + b_5 - b_4 < 0).
又因为(b_1 > 0), 所以不存在这种情况.
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 1e5 + 5;
int n, cnt;
long long suma, sumb, tmpa, tmpb;
struct node { int a, b, id; } x[N], tmp[N];
int cmp(node x, node y) {
return x.a > y.a;
}
int mmp(node x, node y) {
return x.a == y.a ? x.id < y.id : x.a > y.a;
}
int main() {
// freopen("game.in","r",stdin); freopen("game.out","w",stdout);
n = read();
for(int i = 1;i <= n; i++) x[i].a = read(), suma += x[i].a;
for(int i = 1;i <= n; i++) x[i].b = read(), sumb += x[i].b;
for(int i = 1;i <= n; i++) x[i].id = i;
sort(x + 1, x + n + 1, cmp);
tmpa += x[1].a; tmpb += x[1].b; tmp[++ cnt] = x[1];
for(int i = 2;i <= n; i += 2) {
if(x[i].b >= x[i + 1].b) tmpb += x[i].b, tmpa += x[i].a, tmp[++ cnt] = x[i];
else tmpb += x[i + 1].b, tmpa += x[i + 1].a, tmp[++ cnt] = x[i + 1];
}
if(tmpb * 2 <= sumb || tmpa * 2 <= suma) { printf("-1
"); }
else {
printf("%d
", cnt);
sort(tmp + 1, tmp + cnt + 1, mmp);
for(int i = 1;i <= cnt; i++) printf("%d ", tmp[i].id);
}
fclose(stdin); fclose(stdout);
return 0;
}
T2
题目链接
这道题一看还以为是个可持久化数据结构, 没想到乱搞搞就好了.
发现题目要求的操作十分的简单, 只需维护一下01的个数就好了, 所以我们完全没必要去写可持久化.
对于操作是1,2,3类型的, 我们直接往它的上一次操作连边, 对于操作是4类型的, 我们往它要返回的那一次操作连边, 这样就构成了一颗操作树, 我们直接在这颗操作树上(dfs)就可以了.
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int M = 1e3 + 5, K = 1e5 + 5;
int n, m, q_, res, cnt;
int col[M][M], Col[M], num[M], ans[K], head[K];
struct ques { int opt, x, y, f; } q[K];
struct edge { int to, nxt; } e[K << 1];
void add(int x, int y) {
// cout << x << " " << y << "!!!!
";
e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y;
}
void Work(int now, int f) {
// cout << now << " " << f << "------->";
if(f == 0) {
if(q[now].opt == 2) {
if(!Col[q[now].x]) {
if(col[q[now].x][q[now].y]) {
num[q[now].x] --; res --; col[q[now].x][q[now].y] = 0;
}
else q[now].f = 1;
}
else {
if(!col[q[now].x][q[now].y]) {
num[q[now].x] ++; res --; col[q[now].x][q[now].y] = 1;
}
else q[now].f = 1;
}
}
if(q[now].opt == 1) {
if(!Col[q[now].x]) {
if(!col[q[now].x][q[now].y]) {
num[q[now].x] ++; res ++; col[q[now].x][q[now].y] = 1;
}
else q[now].f = 1;
}
else {
if(col[q[now].x][q[now].y]) {
num[q[now].x] --; res ++; col[q[now].x][q[now].y] = 0;
}
else q[now].f = 1;
}
}
if(q[now].opt == 3) {
if(!Col[q[now].x]) res -= num[q[now].x], res += m - num[q[now].x];
else res -= m - num[q[now].x], res += num[q[now].x];
Col[q[now].x] ^= 1;
}
}
else {
if(q[now].opt == 2) {
if(!Col[q[now].x]) {
if(!q[now].f) {
num[q[now].x] ++; res ++; col[q[now].x][q[now].y] = 1;
}
}
else {
if(!q[now].f) {
num[q[now].x] --; res ++; col[q[now].x][q[now].y] = 0;
}
}
}
if(q[now].opt == 1) {
if(!Col[q[now].x]) {
if(!q[now].f) {
num[q[now].x] --; res --; col[q[now].x][q[now].y] = 0;
}
}
else {
if(!q[now].f) {
num[q[now].x] ++; res --; col[q[now].x][q[now].y] = 1;
}
}
}
if(q[now].opt == 3) {
if(!Col[q[now].x]) res -= num[q[now].x], res += m - num[q[now].x];
else res -= m - num[q[now].x], res += num[q[now].x];
Col[q[now].x] ^= 1;
}
}
// cout << res << "
";
}
void dfs(int x) {
// cout << x << "++++++
";
Work(x, 0); ans[x] = res;
// cout << x << " " << ans[x] << " " << res << "+++
";
for(int i = head[x]; i ; i = e[i].nxt) dfs(e[i].to);
Work(x, 1);
// cout << x << " " << ans[x] << " " << res << "---
";
}
int main() {
// freopen("now.in","r",stdin); freopen("now.out","w",stdout);
n = read(); m = read(); q_ = read();
for(int i = 1;i <= q_; i++) {
q[i].opt = read(); q[i].x = read();
if(q[i].opt <= 2) q[i].y = read();
if(q[i].opt == 4) {
add(q[i].x, i);
}
else add(i - 1, i);
}
dfs(0);
for(int i = 1;i <= q_; i++) printf("%d
", ans[i]);
fclose(stdin); fclose(stdout);
return 0;
}
/*
2 3 4
1 1 1
3 2
4 0
1 1 1
999 999 12
2 693 492
1 639 609
4 1
4 0
1 419 528
3 223
1 1 36
4 6
1 75 3
1 327 629
4 8
2 222 216
*/
T3
题目链接
欧拉回路.
由于一些区间是这样的 : ([x,x]). 也就是只覆盖一个点, 我们不太好操作, 于是我们把点转化成线段, 那么每一个区间就变成了([x,x+1])或([x,y+1])了, 这样比较舒服.
我们把红色区间看成+1, 绿色区间看成-1, 最后我们需要每个点(|sum p_i| leq 1).
不会了..............
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 2e5 + 5;
int n, cnt, cnt_b;
int b[N], c[N], s[N], t[N], vis[N], head[N], in_du[N], out_du[N];
struct line { int l, r; } L[N];
struct edge { int f, id, to, nxt; } e[N << 1];
void add(int x, int y, int i) {
e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].id = i;
}
void dfs(int x) {
vis[x] = 1;
for(int i = head[x]; i ; i = e[i].nxt) {
int y = e[i].to; if(e[i].f) continue ;
s[e[i].id] = x; t[e[i].id] = y;
e[i].f = e[i ^ 1].f = 1;
// cout << x << " " << y << "
";
dfs(y);
}
}
int main() {
// freopen("party.in","r",stdin); freopen("party.out","w",stdout);
n = read(); cnt = 1;
for(int i = 1;i <= n; i++) {
L[i].l = read(), L[i].r = read() + 1;
b[++ cnt_b] = L[i].l, b[++ cnt_b] = L[i].r;
}
sort(b + 1, b + cnt_b + 1);
cnt_b = unique(b + 1, b + cnt_b + 1) - b - 1;
for(int i = 1;i <= n; i++) {
L[i].l = lower_bound(b + 1, b + cnt_b + 1, L[i].l) - b;
L[i].r = lower_bound(b + 1, b + cnt_b + 1, L[i].r) - b;
add(L[i].l, L[i].r, i); add(L[i].r, L[i].l, i);
out_du[L[i].l] ++; in_du[L[i].r] ++;
}
for(int i = 1;i <= cnt_b; i++) {
c[i] = c[i - 1] + out_du[i] - in_du[i];
if(c[i] & 1)
add(i, i + 1, n + 1), add(i + 1, i, n + 1);
}
for(int i = 1;i <= cnt_b; i++) if(!vis[i]) dfs(i);
for(int i = 1;i <= n; i++)
printf("%d ", s[i] < t[i] ? 0 : 1);
// fclose(stdin); fclose(stdout);
return 0;
}
/*
2
0 2
2 3
6
1 5
1 3
3 5
2 10
11 11
12 12
*/