[题解]NOIP2015提高组の题解集合
来源:互联网 发布:斧子演示 知乎 编辑:程序博客网 时间:2024/06/05 00:30
Day 1
T1 magic
模拟题。不断地往右上或往下走,注意边界。
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res;}const int N = 55;int n, a[N][N];int main() { //freopen("magic.in", "r", stdin); //freopen("magic.out", "w", stdout); int i, j, x = 1, y; n = read(); y = n + 1 >> 1; for (i = 1; i <= n * n; i++) { a[x][y] = i; if (i % n == 0) x++; else x--, y++; x = (x + n) % n; if (!x) x = n; y = (y + n) % n; if (!y) y = n; } for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) printf("%d ", a[i][j]); printf("\n"); } return 0;}
T2 message
把每个
有很多种做法。其中一种是,从一个点
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res;}const int N = 2e5 + 5, INF = 0x3f3f3f3f;int n, t[N], ans = INF, vis[N], times;void go(int x) { int tmp = times; while (1) { int v = t[x]; if (vis[x] && vis[x] <= tmp) return; if (vis[v] > tmp) return (void) (ans = min(ans, times - vis[v] + 2)); vis[x] = ++times; x = v; }}int main() { //freopen("message.in", "r", stdin); //freopen("message.out", "w", stdout); int i; n = read(); for (i = 1; i <= n; i++) t[i] = read(); for (i = 1; i <= n; i++) if (!vis[i]) go(i); cout << ans << endl; return 0;}
T3 landlords
不考虑顺子,那么一次打多张一定是最优的。所以可以用贪心求解这一部分。对于顺子,就爆搜。
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res;}const int N = 25, INF = 0x3f3f3f3f;int n, cnt[N], typ[] = {0, 13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},Ans, tmp[N];int cc() { int i, CN = 0; memset(tmp, 0, sizeof(tmp)); for (i = 0; i <= 13; i++) tmp[cnt[i]]++; while (tmp[4] >= 1 && tmp[2] >= 2) tmp[4]--, tmp[2] -= 2, CN++; while (tmp[4] >= 1 && tmp[1] >= 2) tmp[4]--, tmp[1] -= 2, CN++; while (tmp[4] >= 1 && tmp[2] >= 1) tmp[4]--, tmp[2]--, CN++; while (tmp[3] >= 1 && tmp[2] >= 1) tmp[3]--, tmp[2]--, CN++; while (tmp[3] >= 1 && tmp[1] >= 1) tmp[3]--, tmp[1]--, CN++; return CN + tmp[1] + tmp[2] + tmp[3] + tmp[4];}void dfs(int dep) { if (dep >= Ans) return; int i, j, k; Ans = min(Ans, dep + cc()); for (i = 2; i <= 13; i++) for (j = 1; j <= 3; j++) { if (cnt[i] < j) continue; int tt = 0; for (k = i; cnt[k] >= j; k++) tt += j, cnt[k] -= j; for (; (--k) >= i;) { if (tt >= 5) dfs(dep + 1); tt -= j, cnt[k] += j; } }}void work() { int i; memset(cnt, 0, sizeof(cnt)); for (i = 1; i <= n; i++) cnt[typ[read()]]++, read(); Ans = INF; dfs(0); printf("%d\n", Ans);}int main() { //freopen("landlords.in", "r", stdin); //freopen("landlords.out", "w", stdout); int T = read(); n = read(); while (T--) work(); return 0;}
Day 2
T1 stone
基础的二分题。二分最短跳跃距离后判定是否可能。
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res;}const int N = 5e4 + 5;int L, n, m, a[N], minv;bool check(int mid) { int i, tot = 0, pre = 0; for (i = 1; i <= n + 1; i++) if (a[i] - pre < mid) tot++; else pre = a[i]; return tot <= m;}int solve() { int l = minv, r = 1e9, mid; while (l <= r) { mid = l + r >> 1; if (check(mid)) l = mid + 1; else r = mid - 1; } return r;}int main() { //freopen("stone.in", "r", stdin); //freopen("stone.out", "w", stdout); int i; L = read(); n = read(); m = read(); for (i = 1; i <= n; i++) a[i] = read(), minv = min(minv, a[i]); a[n + 1] = L; printf("%d\n", solve()); return 0;}
T2 substring
考虑DP。
定义状态
那么很容易得出转移:
1、对于任意一个
2、
3、如果
最后结果即为
考虑到空间问题,滚动
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res;}const int N = 1005, M = 205, PYZ = 1e9 + 7;int n, m, K, f[2][M][M][2];char a[N], b[M];int main() { //freopen("substring.in", "r", stdin); //freopen("substring.out", "w", stdout); int i, j, k; n = read(); m = read(); K = read(); scanf("%s", a + 1); scanf("%s", b + 1); f[0][0][0][0] = 1; for (i = 1; i <= n; i++) { int op = i & 1; f[op][0][0][0] = 1; for (j = 1; j <= min(i, m); j++) for (k = 1; k <= min(j, K); k++) { f[op][j][k][0] = f[op][j][k][1] = 0; f[op][j][k][0] = (f[op ^ 1][j][k][0] + f[op ^ 1][j][k][1]) % PYZ; if (a[i] == b[j]) { f[op][j][k][1] = (f[op ^ 1][j - 1][k][1] + f[op ^ 1][j - 1][k - 1][0]) % PYZ; (f[op][j][k][1] += f[op ^ 1][j - 1][k - 1][1]) %= PYZ; } } } printf("%d\n", (f[n & 1][m][K][0] + f[n & 1][m][K][1]) % PYZ); return 0;}
T3 transport
首先存下每个运输计划的起点
先二分最短时间
在判定中,先标记出所有
这里,为每个点赋予一个权值,初始为
然后对于任意一个
这样容易知道,最后如果一个点的点权等于所有
对于路径加
建立差分数组
对于
而单点询问就是求子树和。最后DFS一遍就可以求出所有点的点权。
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res;}const int N = 3e5 + 5, LogN = 23;int n, m, a[N], ecnt, nxt[N << 1], adj[N], go[N << 1], fa[N][LogN],dep[N], T[N], val[N << 1], dis[N], len[N], st[N], ed[N],maxv, _lca[N], top[N], v_res, cnt_now;void add_edge(int u, int v, int w) { nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;}void dfs(int u, int fu) { int i; dep[u] = dep[fu] + 1; for (i = 1; i <= 21; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int e = adj[u], v; e; e = nxt[e]) { if ((v = go[e]) == fu) continue; fa[v][0] = u; dis[v] = dis[u] + val[e]; top[v] = val[e]; dfs(v, u); }}int lca(int u, int v) { int i; if (dep[u] < dep[v]) swap(u, v); for (i = 21; i >= 0; i--) { if (dep[fa[u][i]] >= dep[v]) u = fa[u][i]; if (u == v) return u; } for (i = 21; i >= 0; i--) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; return fa[u][0];}int dist(int i, int u, int v) { return dis[u] + dis[v] - (dis[_lca[i] = lca(u, v)] << 1);}void change(int i, int x) { T[st[i]] += x; T[ed[i]] += x; T[_lca[i]] -= x << 1;}int dfs_ans(int u, int fu) { int res_d = T[u]; for (int e = adj[u], v; e; e = nxt[e]) { if ((v = go[e]) == fu) continue; res_d += dfs_ans(v, u); } if (res_d == cnt_now) v_res = max(v_res, top[u]); return res_d;}bool check(int mid) { int i, res = 0; for (i = 0; i <= n; i++) T[i] = 0; cnt_now = 0; for (i = 1; i <= m; i++) if (len[i] > mid) cnt_now++, change(i, 1); if (!cnt_now) return 1; v_res = 0; dfs_ans(1, 0); return maxv - v_res <= mid;}int solve() { int l = 0, r = maxv, mid; while (l <= r) { mid = l + r >> 1; if (check(mid)) r = mid - 1; else l = mid + 1; } return l;}int main() { //freopen("transport.in", "r", stdin); //freopen("transport.out", "w", stdout); int i, x, y, z; n = read(); m = read(); for (i = 1; i < n; i++) { x = read(); y = read(); z = read(); add_edge(x, y, z); add_edge(y, x, z); } dfs(1, 0); for (i = 1; i <= m; i++) { st[i] = read(); ed[i] = read(); len[i] = dist(i, st[i], ed[i]); maxv = max(maxv, len[i]); } printf("%d\n", solve()); return 0;}
- [题解]NOIP2015提高组の题解集合
- [题解]NOIP2014提高组の题解集合
- [题解]NOIP2016提高组の题解集合
- [NOIP2015]day1题解集合
- [NOIP2015]提高组初赛答案及题解
- {题解}[jzoj4326]NOIP2015提高组Day2 跳石头
- {题解}[jzoj4328]NOIP2015提高组Day2 运输计划
- Noip2015提高组Day1 “神奇的幻方”题解
- NOIP2015题解
- NOIp2015 题解
- Noip2015 普及组 推销员 题解
- NOIP2015普及组T4salesman题解
- NOIP2015普及组第四题解题报告
- NOIP2015 口胡题解
- NOIP2015运输计划 题解
- NOIP2015 Day1题解
- 【NOIP2015】斗地主题解
- NOIP2015子串题解
- NULL ,nullptr,nullptr_t,0 区别
- C语言基础之字符串(附测试代码)
- JS中 事件冒泡与事件捕获
- 聊天窗口
- 归并排序
- [题解]NOIP2015提高组の题解集合
- codevs1116 四色问题
- ThinkPHP框架访问文件提示No input file specified解决方案
- MongoDB 集合字段匹配查询方法
- 哈夫曼编码
- javascript动态添加网页组件
- 编程的那些事儿(一)
- Linux IPC 3 之 信号量
- 僵尸进程和孤儿进程