怎么老是垫底啊。
不高兴。
似乎 A 掉一道题总比别人慢一些。
A. Paint the Numbers
贪心,从小到大枚举,如果没有被涂色,就新增一个颜色把自己和倍数都涂上。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 100 + 7;
int n;
int a[N], col[N];
inline void work() {
int cnt = 0, ans = 0;
std::sort(a + 1, a + n + 1);
for (int i = 1; i <= n; ++i)
if (!col[i]) {
++ans;
for (int j = i; j <= n; ++j) if (a[j] % a[i] == 0) col[j] = ans;
}
printf("%d\n", ans);
}
inline void init() {
read(n);
for (int i = 1; i <= n; ++i) read(a[i]);
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
B. Koala and Lights
状态的循环节不会超过 \(\operatorname{lcm}(1..10)\),所以直接暴力。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 100 + 7;
const int M = 100000 + 7;
int n;
char s[N];
int a[N], b[N];
inline void work() {
int ans = 0;
for (int i = 0; i <= 100000; ++i) {
int cnt = 0;
for (int j = 1; j <= n; ++j)
if (s[j] == '0' && (i >= b[j] && 0 <= (i - b[j]) % a[j] && (i - b[j]) % a[j] < a[j] / 2)) ++cnt;
else if (s[j] == '1' && (i >= b[j] && (i - b[j]) % a[j] >= a[j] / 2)) ++cnt;
else if (s[j] == '1' && i < b[j]) ++cnt;
smax(ans, cnt);
// dbg("i = %d, cnt = %d\n", i, cnt);
}
printf("%d\n", ans);
}
inline void init() {
read(n);
scanf("%s", s + 1);
for (int i = 1; i <= n; ++i) read(a[i]), read(b[i]), a[i] <<= 1;
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
C. Paint the Digits
一开始没读懂题目,以为是只要涂 \(1\) 的单调不降,涂 \(2\) 的也单调不降就可以了。
写了一发然后 Wa1。。。
实际上是把所有涂 \(2\) 的一次接在涂 \(1\) 的后面,整个单调不降。
既然这样,那么就先把所有数排序,然后先找到最前面的几个原坐标上升的全部选为 \(1\)。然后贪心的把后面的开始不满足的那个值,位于之间的最后一个坐标的后面的全部选为 \(1\)。然后剩下的都是 \(2\),判断一下合不合法。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 2e5 + 7;
int n;
char a[N], ans[N];
int kk[N];
pii b[N];
inline void work() {
std::sort(b + 1, b + n + 1);
int pos = -1;
ans[b[1].se] = '1';
for (int i = 2; i <= n; ++i) if (b[i].se < b[i - 1].se) {
pos = i;
// dbg("------------");
break;
} else ans[b[i].se] = '1';//, dbg("*** %d\n", b[i].se);
if (pos == -1) {
for (int i = 1; i <= n; ++i) putchar('1');
puts("");
return;
}
int nn = b[pos].fi, pp = b[pos - 1].se;
for (int i = pos; i <= n; ++i)
if (b[i].fi == nn && b[i].se > pp) ans[b[i].se] = '1';
kk[0] = 0;
for (int i = 1; i <= n; ++i) if (ans[i] == '1') kk[++kk[0]] = a[i];//, dbg("*** %d\n", i);
for (int i = 1; i <= n; ++i) if (ans[i] == '2') kk[++kk[0]] = a[i];
if (!std::is_sorted(kk + 1, kk + n + 1)) puts("-");
else {
for (int i = 1; i <= n; ++i) putchar(ans[i]);
puts("");
}
}
inline void init() {
read(n);
scanf("%s", a + 1);
for (int i = 1; i <= n; ++i) a[i] -= '0', b[i] = pii(a[i], i), ans[i] = '2';
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
int T;
read(T);
while (T--) {
init();
work();
}
fclose(stdin), fclose(stdout);
return 0;
}
D. Cow and Snacks
至少有一个人会吃到两份,不妨设其中的一份为 \(A\)。那么剩下来的所有人的两种备选食物中有 \(A\) 的,都只能去吃另一份了,设这一份为 \(C\),那么再剩下来的所有人的备选食物中有 \(C\) 的也都只能去另一份……以此类推。
可以发现这样的关系实际上是一棵树,所以随便求一个生成树就可以了。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 1e5 + 7;
int n, m, ans;
int dep[N], vis[N];
struct Edge { int to, ne; } g[N << 1]; int head[N], tot = 1;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }
inline void dfs(int x, int fr = -1, int fa = 0) {
vis[x] = 1, dep[x] = dep[fa] + 1;
for fec(i, x, y) if ((i ^ fr) != 1) {
// dbg("****** %d %d\n", x, y);
if (!vis[y]) dfs(y, i, x);
else if (dep[y] > dep[x]) ++ans;
}
}
inline void work() {
for (int i = 1; i <= n; ++i) if (!vis[i]) dfs(i);
printf("%d\n", ans);
}
inline void init() {
read(n), read(m);
for (int i = 1; i <= m; ++i) {
int x, y;
read(x), read(y);
adde(x, y);
}
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
E. Rotate Columns
很容易想到一个暴力:
设 \(f[i][S]\) 表示第 \(i\) 列中,选了 \(S\) 中的行的位置的数的最大和。这个可以通过 \(O(mn2^n)\) 预处理出来。
然后 \(dp[i][S]\) 表示前 \(i\) 列已经占据了 \(S\) 中的每一行的最大和。这个直接枚举子集转移,时间复杂度 \(O(m3^n)\)。
可以通过 Easy Version。
然后考虑,是否每一列都是有必要的。可以发现,只有最大值最大的 \(n\) 列才是有用的,因为不管怎么说,只要有了这 \(n\) 列,即使每一列的最大值直接填补每一行,都可以得到一个不错的结果。而想要更优,也只能是在这几列里面选择。可以这要考虑,如果有两行不是在这 \(n\) 列中选的,那么这 \(n\) 列中至少有两列没有被用上,只需要用这两列的最大值代替不是在这 \(n\) 列中选的两行得到的结果一定更优。
然后复杂度降低为 \(O(n^22^n+n3^n)\)。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 15;
const int M = 2000 + 7;
const int NP = (1 << 12) + 7;
int n, m, S;
int a[N][M], dp[M][NP], f[M][NP], tt[NP];
pii bb[M], b[N][M];
inline void work() {
for (int j = 1; j <= m; ++j) {
int mx = 0;
for (int i = 1; i <= n; ++i) smax(mx, a[i][j]);
bb[j] = pii(-mx, j);
}
std::sort(bb + 1, bb + m + 1);
smin(m, n);
S = (1 << n) - 1;
for (int jj = 1; jj <= m; ++jj) {
int j = bb[jj].se;
for (int s = 0; s <= S; ++s) tt[s] = 0, f[jj][s] = 0;
for (int s = 0; s <= S; ++s)
for (int i = 1; i <= n; ++i) if ((s >> (i - 1)) & 1) tt[s] += a[i][j];
for (int s = 0; s <= S; ++s)
for (int i = 1; i <= n; ++i) smax(f[jj][s], tt[(s >> i) | ((s & ((1 << i) - 1)) << (n - i))]);
// for (int s = 0; s <= S; ++s) dbg("f[%d][%d] = %d, tt = %d\n", j, s, f[j][s], tt[s]);
}
for (int j = 1; j <= m; ++j) {
for (int s = 0; s <= S; ++s) dp[j][s] = f[j][s];
for (int s = 0; s <= S; ++s)
for (int sta = s; sta; sta = (sta - 1) & s) smax(dp[j][s], dp[j - 1][sta] + f[j][s ^ sta]);
// for (int s = 0; s <= S; ++s) dbg("dp[%d][%d] = %d\n", j, s, dp[j][s]);
}
printf("%d\n", dp[m][S]);
}
inline void init() {
read(n), read(m);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) read(a[i][j]);
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
int T;
read(T);
while (T--) {
init();
work();
}
fclose(stdin), fclose(stdout);
return 0;
}
F. Koala and Notebook
因为要的是数值最小(比赛的时候一直以为是字典序最小),所以最优的位数可以直接求出了。
那么位数固定了以后,我们可以把原来的每一条边都拆成边权的位数条边,每一条的边权是每一位,这样走一条边的时候一定是一位了。
然后类似于 NOIP2018D2T1 直接贪心走最小的边权(要保证边通往的点的答案的位数一定恰好比当前点大 \(1\))就可以了。
不过这里有一个问题,就是每一个点可能会有很多条边权相同的边。所以我们类似于 01bfs,每次将所有的答案一样的点放到一起,统一从小到大枚举边权以后再枚举每一个点来扩展。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 1e5 * 11 + 7;
const int P = 1e9 + 7;
int n, m, nod, hd, tl;
int buf[10], dis[N], q[N], ans[N];//, pre[N], prec[N];
std::vector<int> g[N][10];
inline void bfs() {
int hd = 0, tl = 1;
q[hd = 0, tl = 1] = 1, dis[1] = 1;
while (hd < tl) {
int l = hd + 1, r = l;
while (r < tl && ans[q[r + 1]] == ans[q[l]]) ++r;
// dbg("i = %d, r = %d, tl = %d\n", i, r, tl);
for (int j = 0; j < 10; ++j)
for (int k = l; k <= r; ++k) {
int x = q[k];
// dbg("x = %d\n", x);
for (int y : g[x][j]) if (!dis[y]) {
dis[y] = dis[x] + 1;
ans[y] = (ans[x] * 10ll + j) % P;
q[++tl] = y;
}
}
hd = r;
}
}
/*
inline void dfs(int x) {
// dbg("x = %d, ans[x] = %d\n", x, ans[x]);
vis[x] = 1;
for (int i = 0; i < 10; ++i) {
int y = g[x][i];
if (!y || dis[y] != dis[x] + 1 || vis[y]) continue;
ans[y] = (ans[x] * 10ll + i) % P;
dfs(y);
}
}*/
inline void work() {
bfs();
// dfs(1);
// if (m == 99681) {
// int x = 133 + 1;
// for (; x; x = pre[x]) printf("** %d %d\n", x, ans[x]);
// }
for (int i = 2; i <= n; ++i) printf("%d\n", ans[i]);
}
inline void init() {
read(n), read(m);
nod = n;
for (int i = 1; i <= m; ++i) {
int xx, yy, z, x, y;
read(xx), read(yy);
if (xx > yy) std::swap(xx, yy);
z = i, x = xx, buf[0] = 0;
while (z) buf[++buf[0]] = z % 10, z /= 10;
while (buf[0] > 1) {
g[x][buf[buf[0]--]].pb(++nod);
x = nod;
// dbg("i = %d, x = %d\n", i, x);
}
g[x][buf[buf[0]]].pb(yy);
if (xx == 1) continue;
z = i, y = yy, buf[0] = 0;
while (z) buf[++buf[0]] = z % 10, z /= 10;
while (buf[0] > 1) {
g[y][buf[buf[0]--]].pb(++nod);
y = nod;
}
g[y][buf[buf[0]]].pb(xx);
}
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
G1. Into Blocks (easy version)
同一个数值必须在同一块中。于是考虑把每一个数值的最左边和最右边搞出来形成 \(m\) 个区间,然后对于所有相交的区间必须在同一块。那么形成了很多块以后每一个块内统计一下哪一种数值的出现次数最多,统一改成这个数值。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 200000 + 7;
int n, m, q, mm;
int a[N], kk[N], cc[N];
struct Int {
int l, r;
} b[N];
inline void work() {
for (int i = 1; i <= m; ++i) b[i].r = 0, b[i].l = n + 1;
for (int i = 1; i <= n; ++i) smin(b[a[i]].l, i), smax(b[a[i]].r, i);
mm = 0;
for (int i = 1; i <= m; ++i) if (b[i].r >= b[i].l) b[++mm] = b[i];//, dbg("*** %d %d\n", b[i].l, b[i].r);
std::sort(b + 1, b + mm + 1, [](const Int &a, const Int &b) {
return a.l < b.l;
});
int rr = 0, lr = 0, ans = 0;
for (int i = 1; i <= mm; ++i) {
if (rr < b[i].l) {
kk[0] = 0;
int cnt = n + 1;
for (int j = lr; j <= rr; ++j) {
if (!cc[a[j]]) kk[++kk[0]] = a[j];
++cc[a[j]];
}
for (int j = 0; j <= kk[0]; ++j) smin(cnt, rr - lr + 1 - cc[kk[j]]), cc[kk[j]] = 0;
lr = b[i].l, ans += cnt;
}
smax(rr, b[i].r);
}
kk[0] = 0;
int cnt = n + 1;
for (int j = lr; j <= n; ++j) {
if (!cc[a[j]]) kk[++kk[0]] = a[j];
++cc[a[j]];
}
for (int j = 0; j <= kk[0]; ++j) smin(cnt, rr - lr + 1 - cc[kk[j]]), cc[kk[j]] = 0;
ans += cnt;
printf("%d\n", ans);
}
inline void init() {
read(n), read(q);
for (int i = 1; i <= n; ++i) read(a[i]), smax(m, a[i]);
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
未完待续
原文地址:https://www.cnblogs.com/hankeke/p/CF1209.html