比赛链接:传送门
前期大顺风,2:30金区中游。后期开题乏力,掉到银尾。4:59绝杀I,但罚时太高卡在银首。
Problem A - Dogs and Cages 00:09:45 (+) Solved by Dancepted
算了半天发现就是n-1,被队友喷死,差点气哭。
Problem E - Evil Forest 00:16:54 (+) Solved by xk
xk大喊签到,就过了。
代码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 100005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1< #define sz(x) ((int)x.size()) #define upperdiv(a,b) (a/b + (a%b>0)) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef long long ll; typedef double db; /** fast read **/ template inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template inline void read(T &x, Args &... args) { read(x), read(args...); } template inline void write(T x) { int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x; do{++len; c[len] = x%10 + '0';} while (x /= 10); for (int i = len; i >= 1; i--) putchar(c[i]); } template inline void write(T x, Args ... args) { write(x), write(args...); } int main() { fast; int T, kase = 1; cin >> T; while (T--) { int n; cin >> n; int ans = 0; for(int i = 0; i < n; i++) { int x; cin >> x; ans += x + upperdiv(x, 10); } cout << "Case #" << (kase++) << ": " << ans << endl; } return 0; } View Code Problem C - Rich Game 00:32:42 (+) Solved by xk xk又喊了一声签到! 代码: #include #include #include #include #include #include #include #include #include #include #include #include #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define N 100005 #define M 100005 #define INF 0x3f3f3f3f #define mk(x) (1< #define sz(x) ((int)x.size()) #define upperdiv(a,b) (a/b + (a%b>0)) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef long long ll; typedef double db; /** fast read **/ template inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template inline void read(T &x, Args &... args) { read(x), read(args...); } template inline void write(T x) { int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x; do{++len; c[len] = x%10 + '0';} while (x /= 10); for (int i = len; i >= 1; i--) putchar(c[i]); } template inline void write(T x, Args ... args) { write(x), write(args...); } int main() { fast; int T, kase = 1; cin >> T; while (T--) { int x, y, k; cin >> x >> y >> k; int money = 0, ans = 0; if(x > y) ans = k; else { for(int i = 0; i < k; i++) { if(money + 9 * x >= 11 * y) { money += 9 * x - 11 * y; ans++; } else { money += 11 * x; } } } cout << "Case #" << (kase++) << ": " << ans << endl; } return 0; } View Code Problem K - Knightmare 00:46:33 (+) Solved by Dancepted 步数较少的时候可以往回走,把没走过的地方填上,步数增长到一定程度时,答案差不多会均匀增长。 我猜测是小数据打表,大数据是个公式之类的。 开完A趁电脑没人就打了个表,发现和我的猜测是一致的,果断交了一发就过了。 代码: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define N 1005 #define M 100005 #define INF 0x3f3f3f3f #define mk(x) (1< #define sz(x) ((int)x.size()) #define upperdiv(a,b) (a/b + (a%b>0)) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef __int128 ll; typedef double db; /** fast read **/ template inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template inline void read(T &x, Args &... args) { read(x), read(args...); } template inline void write(T x) { int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x; do{++len; c[len] = x%10 + '0';} while (x /= 10); for (int i = len; i >= 1; i--) putchar(c[i]); } template inline void write(T x, Args ... args) { write(x), write(args...); } const int ans[10] = {1, 9, 41, 109, 205, 325}; int main() { int T; cin >> T; int kase = 1; while (T--) { ll n; read(n); printf("Case #%d: ", kase++); if (n <= 5) { write(ans[n]); } else { ll res = 14 * n * n - 6 * n + 5; write(res); } putchar('\n'); } return 0; } View Code Problem J - Subway Chasing 01:42:00 (+) Solved by xk & lh 好像是差分约束什么的。图论这种事相信队友就完了。 代码: #include #include #include #include #include #include #include #include #include #include #include #include #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define N 100005 #define M 100005 #define INF 0x3f3f3f3f #define mk(x) (1< #define sz(x) ((int)x.size()) #define upperdiv(a,b) (a/b + (a%b>0)) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef long long ll; typedef double db; /** fast read **/ template inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template inline void read(T &x, Args &... args) { read(x), read(args...); } template inline void write(T x) { int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x; do{++len; c[len] = x%10 + '0';} while (x /= 10); for (int i = len; i >= 1; i--) putchar(c[i]); } template inline void write(T x, Args ... args) { write(x), write(args...); } const int maxn = 2000 + 5; struct edge { int v, l; }; ll dis[maxn]; int cnt[maxn]; bool inq[maxn]; vector void addedge(int u, int v, int l) { g[u].push_back(edge{v, l}); // g[v].push_back(edge{u, l}); } int n, m, x; bool spfa() { queue dis[1] = 0; q.push(1); cnt[1] = inq[1] = 1; while(!q.empty()) { int u = q.front(); inq[u] = 0; q.pop(); for(auto &e : g[u]) { if(dis[e.v] > dis[u] + e.l) { dis[e.v] = dis[u] + e.l; if(!inq[e.v]) { cnt[e.v]++; if(cnt[e.v] >= n) return false; q.push(e.v); inq[e.v] = 1; } } } } return true; } int main() { fast; int T, kase = 1; cin >> T; while (T--) { cin >> n >> m >> x; for(int i = 1; i <= n; i++) { g[i].clear(); dis[i] = 1e18; cnt[i] = inq[i] = 0; } for(int i = 1; i < n; i++) { addedge(i+1, i, -1); addedge(i, i+1, 2e9); } for(int i = 0; i < m; i++) { int a, b, c, d; cin >> a >> b >> c >> d; if(a == b) { if(c == d) { addedge(a, c, x); addedge(c, a, -x); } else { addedge(a, c, x - 1); addedge(d, a, -x - 1); } } else { if(c == d) { addedge(b, c, x - 1); addedge(c, a, -x - 1); } else { addedge(b, c, x - 1); addedge(d, a, -x - 1); } } } cout << "Case #" << (kase++); if(!spfa()) cout << " IMPOSSIBLE\n"; else { for(int i = 2; i <= n; i++) cout << ' ' << dis[i] - dis[i - 1]; cout << endl; } } return 0; } View Code Problem G - Alice’s Stamps 02:24:14 (-2) Solved by Dancepted (dp) 上机的时候思路有乱,调出来之后交上去因为N开大了MLE返回CE,贡献了两发罚时。 dfs枚举当前搜索过的最右端点和剩下的k的数量,记忆化一下,状态数最多就$O(n^{2})$。 HDU的T组数据比较玄学,差点没敢交。 代码:$O(n^{2})$ #include #include #include #include #include #include #include #include #include #include #include #include #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define N 2005 #define M 100005 #define INF 0x3f3f3f3f #define mk(x) (1< #define sz(x) ((int)x.size()) #define upperdiv(a,b) (a/b + (a%b>0)) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef long long ll; typedef double db; /** fast read **/ template inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template inline void read(T &x, Args &... args) { read(x), read(args...); } template inline void write(T x) { int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x; do{++len; c[len] = x%10 + '0';} while (x /= 10); for (int i = len; i >= 1; i--) putchar(c[i]); } template inline void write(T x, Args ... args) { write(x), write(args...); } struct Node{ int l, r; bool operator < (const Node& x) const { if (r == x.r) { return l < x.l; } return r < x.r; } }; int n, m, k; vector int ans = 0; int f[N][N]; int dfs(int id, int r, int cnt, int resk) { if (f[r][resk]) { return f[r][resk]; } if (resk == 0) { return 0; } if (id >= sz(ns)) { return 0; } int tmp = dfs(id+1, r, cnt, resk); tmp = max(tmp, ns[id].r - max(ns[id].l-1, r) + dfs(id+1, ns[id].r, cnt + ns[id].r - max(ns[id].l-1, r), resk-1)); ans = max(ans, cnt + tmp); return f[r][resk] = tmp; } bool ok[N]; int l[N], r[N]; int main() { int T, kase = 1; cin >> T; while (T--) { ns.clear(), ns1.clear(); read(n, m, k); for (int i = 1; i <= m; i++) { read(l[i], r[i]); ok[i] = true; } for (int i = 1; i <= m; i++) { for (int j = 1; j <= m; j++) if (i != j) { if (l[i] < l[j] && r[j] <= r[i]) { ok[j] = false; } } } for (int i = 1; i <= m; i++) if (ok[i]) { ns.push_back(Node{l[i], r[i]}); } sort(ns.begin(), ns.end()); // init(); ans = 0; for (int i = 0; i <= n; i++) { for (int j = 0; j <= k; j++) { f[i][j] = 0; } } dfs(0, 0, 0, k); printf("Case #%d: %d\n", kase++, ans); } return 0; } View Code 题解的做法是一个很好写的dp: $f_{i, j}$表示最右边的覆盖点是i的情况下,用了j个集合的最大覆盖长度。 代码:$O(n^{2})$ #include #include #include #include #include #include #include #include #include #include #include #include #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define N 2005 #define M 100005 #define INF 0x3f3f3f3f #define mk(x) (1< #define sz(x) ((int)x.size()) #define upperdiv(a,b) (a/b + (a%b>0)) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef long long ll; typedef double db; /** fast read **/ template inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template inline void read(T &x, Args &... args) { read(x), read(args...); } template inline void write(T x) { int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x; do{++len; c[len] = x%10 + '0';} while (x /= 10); for (int i = len; i >= 1; i--) putchar(c[i]); } template inline void write(T x, Args ... args) { write(x), write(args...); } int mxr[N]; int f[N][N]; int main() { int T; cin >> T; for (int kase = 1; kase <= T; kase++) { int n, m, k; read(n, m, k); memset(mxr, 0, (n+1) * sizeof(int)); for (int i = 0; i <= n; i++) { for (int j = 0; j <= k; j++) { f[i][j] = 0; } } for (int i = 1; i <= m; i++) { int l, r; read(l, r); mxr[l] = max(mxr[l], r); } int ans = 0, r = 0; for (int i = 1; i <= n; i++) { r = max(mxr[i], r); for (int j = 0; j <= k; j++) { f[i][j] = max(f[i][j], f[i-1][j]); ans = max(ans, f[i][j]); if (j+1 <= k) f[r][j+1] = max(f[r][j+1], f[i-1][j] + r - i + 1), ans = max(ans, f[r][j+1]); } } printf("Case #%d: %d\n", kase, ans); } return 0; } View Code Problem I - Inkopolis 04:59:59 (-3) Solved by Dancepted & xk 中午还在看的基环树下午就用到了。 先考虑树上的情况。会影响答案的部分只有修改颜色之前的颜色$color_{pre}$,和之后的颜色$color_{now}$两种。看是否会新增、删除color region,或者合并、分割原来的color region。 再考虑环上的情况。同上。特别地:如果整个环都是同一种颜色,修改了颜色不会分割原来的color region;如果整个环除了修改的边都是$color_{now}$,则修改颜色不会合并color region。 计算节日开始前各街道的颜色,可以模仿修改的操作,一条条边加入就行了。 实现的时候先把环扣出来,统计一下环各颜色的边数量。用个map保存每个点相邻的各颜色的数量。再用map保存每条边的颜色。 然后扫一遍所有的边先计算初始情况下的region的数量sum,然后一次次修改边的颜色,更新sum就好了。 代码:O(nlogn) #include #include #include #include #include #include #include #include #include #include #include #include #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define N 200005 #define M 200005 #define INF 0x3f3f3f3f #define mk(x) (1< #define sz(x) ((int)x.size()) #define upperdiv(a,b) (a/b + (a%b>0)) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef long long ll; typedef double db; /** fast read **/ template inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template inline void read(T &x, Args &... args) { read(x), read(args...); } template inline void write(T x) { int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x; do{++len; c[len] = x%10 + '0';} while (x /= 10); for (int i = len; i >= 1; i--) putchar(c[i]); } template inline void write(T x, Args ... args) { write(x), write(args...); } int tot; int head[N], nxt[N<<1], ver[N<<1], col[N<<1]; void addEdge(int u, int v, int c) { nxt[tot] = head[u], ver[tot] = v, col[tot] = c, head[u] = tot++; } int iscir[N], cirlen; bool vis[N]; int getCir(int u, int fa, int& rt) { vis[u] = true; for (int i = head[u]; i != -1; i = nxt[i]) { int v = ver[i]; if (v == fa) continue; if (vis[v]) { rt = v; iscir[u] = 1; cirlen++; return 1; } else { int tmpcir = getCir(v, u, rt); if (tmpcir) { iscir[u] = tmpcir; cirlen++; return u != rt; } } } return 0; } int cnt[N]; int sum; map map void update(int u, int v, int ccur, bool ifprint) { if (u > v) swap(u, v); int cpre = uv_col[mp(u, v)]; if (cpre == ccur) { if (ifprint) printf("%d\n", sum); return; } if (!iscir[u] || !iscir[v]) { //on tree if (mp[u][cpre] >= 2 && mp[v][cpre] >= 2) { sum++; } if (mp[u][cpre] == 1 && mp[v][cpre] == 1) { sum--; } if (mp[u][ccur] && mp[v][ccur]) { sum--; } if (!mp[u][ccur] && !mp[v][ccur]) { sum++; } } else { //on circle if (mp[u][cpre] >= 2 && mp[v][cpre] >= 2) { if (cnt[cpre] != cirlen) sum++; } if (mp[u][cpre] == 1 && mp[v][cpre] == 1) { sum--; } if (mp[u][ccur] && mp[v][ccur]) { if (cnt[ccur] != cirlen-1) sum--; } if (!mp[u][ccur] && !mp[v][ccur]) { sum++; } if (cpre != -1) cnt[cpre]--; cnt[ccur]++; } uv_col[mp(u, v)] = ccur; if (cpre != -1) { mp[u][cpre]--; mp[v][cpre]--; } mp[u][ccur]++; mp[v][ccur]++; if (ifprint) printf("%d\n", sum); } int main() { int T; cin >> T; for (int kase = 1; kase <= T; kase++) { int n, m; read(n, m); // init uv_col.clear(); for (int i = 1; i <= n; i++) { mp[i].clear(); } tot = 0; memset(head, -1, (n+1) * sizeof(int)); // input and count colors on every edge for (int i = 1; i <= n; i++) { int u, v, c; read(u, v, c); addEdge(u, v, c); addEdge(v, u, c); if (u > v) swap(u, v); uv_col[mp(u, v)] = -1; // mp[u][c]++; mp[v][c]++; } // get circle int rt = -1; memset(vis, false, (n+1) * sizeof(bool)); memset(iscir, 0, (n+1) * sizeof(int)); cirlen = 0; getCir(1, -1, rt); // count colors on circle memset(cnt, 0, (n+1) * sizeof(int)); sum = 0; for (int i = 0; i < n; i++) { int u = ver[i<<1], v = ver[i<<1|1], ccur = col[i<<1]; update(u, v, ccur, false); } printf("Case #%d:\n", kase); for (int i = 1; i <= m; i++) { int u, v, ccur; read(u, v, ccur); update(u, v, ccur, true); } } return 0; } /* 11111 5 10 1 5 1 2 5 1 3 5 1 4 5 1 1 2 1 1 2 1 2 4 4 1 2 1 2 3 1 3 4 1 4 1 1 1 2 2 3 4 2 2 3 2 4 1 4 4 3 4 2 4 2 3 3 3 4 2 1 4 1 3 4 2 2 3 4 3 4 3 */ View Code 总结: 本场能绝杀还是有点运气成分在的,而且现场赛的话最后几分钟可能就交不上题了也可能。不过绝杀也不影响苟在银牌,问题不大。 然后最近的几场好像都是我在贡献罚时,感觉码力出现了一些小小的问题。这两天要小心一点。 然后还有两周可能就要退役了,模拟赛还没有进过金区感觉很难受啊,打成这个样子还怎么冲金啊qaq。
