NOIP2014解题报告
day 1
1.生活大爆炸版石头剪刀布(rps)
直接按照题意模拟即可
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 | #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 209; const int Mark[5][5] = {{0, 0, 1, 1, 0}, {1, 0, 0, 1, 0}, {0, 1, 0, 0, 1}, {0, 0, 1, 0, 1}, {1, 1, 0, 0, 0}}; int N, Na, Nb; int a[maxn], b[maxn]; int main() { scanf ( "%d%d%d" , &N, &Na, &Nb); for ( int i = 0; i < Na; i++) scanf ( "%d" , a + i); for ( int i = 0; i < Nb; i++) scanf ( "%d" , b + i); int ansa = 0, ansb = 0, pa = 0, pb = 0; while (N--) { ansa += Mark[a[pa]][b[pb]]; ansb += Mark[b[pb]][a[pa]]; if ((++pa) >= Na) pa -= Na; if ((++pb) >= Nb) pb -= Nb; } printf ( "%d %d\n" , ansa, ansb); return 0; } |
2.联合权值(link)
比较基础的树形dp. mxx,cntx表示以x为根的子树中结点x的孩子的最大权值和总权值, 在对树进行dfs时计算出结果.
时间复杂度O(N)
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespace std; const int maxn = 200009; const int MOD = 10007; int N, w[maxn], mx[maxn], cnt[maxn], ans = 0, tot = 0; inline int read() { char c = getchar (); int ret = 0; for (; ! isdigit (c); c = getchar ()); for (; isdigit (c); c = getchar ()) ret = ret * 10 + c - '0' ; return ret; } struct edge { int to; edge* next; } E[maxn << 1], *pt = E, *head[maxn]; inline void add( int u, int v) { pt->to = v; pt->next = head[u]; head[u] = pt++; } inline void addedge( int u, int v) { add(u, v); add(v, u); } void init() { scanf ( "%d" , &N); for ( int i = 1; i < N; i++) { int u = read() - 1, v = read() - 1; addedge(u, v); } for ( int i = 0; i < N; i++) scanf ( "%d" , w + i); } void dfs( int x, int fa = -1) { mx[x] = cnt[x] = 0; for (edge* e = head[x]; e; e = e->next) if (e->to != fa) { dfs(e->to, x); ans = max(ans, w[x] * mx[e->to]); ans = max(ans, w[e->to] * mx[x]); tot = (tot + w[x] * cnt[e->to] + w[e->to] * cnt[x]) % MOD; (cnt[x] += w[e->to]) %= MOD; mx[x] = max(mx[x], w[e->to]); } } int main() { init(); dfs(0); printf ( "%d %d\n" , ans, tot * 2 % MOD); return 0; } |
3.飞扬的小鸟(bird)
完全背包, dp(x, y)表示小鸟在坐标(x, y)处的最小点击屏幕数.
从左到右dp, 状态转移方程为 dp(x, y) = min{dp(x-1,y-INCx-1)+1,dp(x,y-INCx-1)+1,dp(x,y+DECx-1)}
其中INCx表示横坐标为x点击一次屏幕的上升高度.
我们知道完全背包是要顺序枚举, 这道题也是, y要从1开始枚举. 还要注意先算点击屏幕的, 再算不点击屏幕让bird自己下来的, 这样才不会重复. 不能到达终点就在dp过程中算一算.
时间复杂度O(NM)
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 44 45 46 47 48 49 50 51 52 53 54 55 | #include<cstring> #include<algorithm> #include<cstdio> using namespace std; const int maxn = 10009; const int inf = 0x3f3f3f3f; int N, V, n; int Inc[maxn], Dec[maxn], L[maxn], R[maxn], dp[2][maxn]; void init() { scanf ( "%d%d%d" , &N, &V, &n); for ( int i = 0; i < N; i++) scanf ( "%d%d" , Inc + i, Dec + i); for ( int i = 1; i <= N; i++) L[i] = 0, R[i] = V + 1; while (n--) { int p; scanf ( "%d" , &p); scanf ( "%d%d" , L + p, R + p); } } int main() { init(); int c = 0, p = 1, cnt = 0; memset (dp, inf, sizeof dp); for ( int i = 1; i <= V; i++) dp[c][i] = 0; for ( int i = 1; i <= N; i++) { swap(c, p); memset (dp[c], inf, sizeof dp[c]); for ( int j = 1; j <= V; j++) if (j - Inc[i - 1] > 0) dp[c][j] = min(dp[c][j], min(dp[c][j - Inc[i - 1]], dp[p][j - Inc[i - 1]]) + 1); for ( int j = V - Inc[i - 1]; j <= V; j++) dp[c][V] = min(dp[c][V], min(dp[p][j], dp[c][j]) + 1); for ( int j = 1; j <= V; j++) if (j + Dec[i - 1] <= V) dp[c][j] = min(dp[c][j], dp[p][j + Dec[i - 1]]); for ( int j = 1; j <= L[i]; j++) dp[c][j] = inf; for ( int j = R[i]; j <= V; j++) dp[c][j] = inf; bool F = false ; for ( int j = L[i]; ++j < R[i]; ) F |= dp[c][j] < inf; if (!F) { printf ( "0\n%d\n" , cnt); return 0; } if (R[i] <= V) cnt++; } int ans = inf; for ( int i = L[N]; ++i < R[N]; ) ans = min(ans, dp[c][i]); printf ( "1\n%d\n" , ans); return 0; } |
day1的题目总体上比较简单, 或者说有点过于简单了.
day 2
1.无限网路发射器选址(wrieless)
直接枚举每一个点, 再对于每一个点暴力算即可.
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 | #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 139; int w[maxn][maxn]; int main() { memset (w, 0, sizeof w); int d, n; scanf ( "%d%d" , &d, &n); while (n--) { int x, y; scanf ( "%d%d" , &x, &y); scanf ( "%d" , w[x] + y); } int tot, ans = 0; for ( int i = 0; i < 129; i++) for ( int j = 0; j < 129; j++) { int cnt = 0; for ( int a = max(0, i - d); a <= min(128, i + d); a++) for ( int b = max(0, j - d); b <= min(128, j + d); b++) cnt += w[a][b]; if (cnt > ans) tot = 1, ans = cnt; else if (cnt == ans) tot++; } printf ( "%d %d\n" , tot, ans); return 0; } |
2.寻找道路(road)
先从终点反向dfs一遍标出T能到达的点, 然后对于每个点检查它的出边是否被标记来确定是否可经过此点. 然后跑最短路即可.
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int maxn = 10009; const int inf = 0x3f3f3f3f; struct edge { int to; edge* next; } E[400009], *pt = E, *head[maxn]; void addedge( int u, int v) { pt->to = v; pt->next = head[u]; head[u] = pt++; } int N, S, T, d[maxn]; bool vis[maxn], ok[maxn], inq[maxn]; queue< int > q; int sp() { if (!ok[S]) return -1; memset (d, inf, sizeof d); memset (inq, 0, sizeof inq); d[S] = 0; q.push(S); inq[S] = true ; while (!q.empty()) { int x = q.front(); q.pop(); for (edge* e = head[x]; e; e = e->next) if (ok[e->to] && d[e->to] > d[x] + 1) { d[e->to] = d[x] + 1; if (!inq[e->to]) q.push(e->to), inq[e->to] = true ; } } return d[T] != inf ? d[T] : -1; } namespace G { edge* head[maxn]; void addedge( int u, int v) { pt->to = v; pt->next = head[u]; head[u] = pt++; } void dfs( int x) { if (vis[x]) return ; vis[x] = true ; for (edge* e = head[x]; e; e = e->next) dfs(e->to); } } int main() { memset (vis, 0, sizeof vis); int m; scanf ( "%d%d" , &N, &m); while (m--) { int x, y; scanf ( "%d%d" , &x, &y); x--; y--; if (x == y) continue ; addedge(x, y); G::addedge(y, x); } scanf ( "%d%d" , &S, &T); S--; T--; G::dfs(T); for ( int i = 0; i < N; i++) { ok[i] = true ; if (!vis[i]) { ok[i] = false ; continue ; } for (edge* e = head[i]; e; e = e->next) if (!vis[e->to]) ok[i] = false ; } printf ( "%d\n" , sp()); return 0; } |
3.解方程(equation)
当f(x) = 0时, f(x) mod p = 0. 那么当f(x) mod p = 0时f(x)就有可能=0.
我们可以取几个质数, 然后对于[1,m]每一个都进行验证. 只需算出x在[1,p)中的结果即可, x在[p,m]上, f(x) mod p = f(x%p) mod p.
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 44 45 46 47 48 49 50 51 52 53 | #include<cstdio> #include<cstring> #include<algorithm> #include<cctype> using namespace std; const int p[] = {20011, 20021, 20023, 20029, 20047}; const int maxn = 209; const int pn = 5; int a[pn][maxn], f[pn][23000], N, M; int ans[1000009], n = 0; void Read( int x) { bool F = true ; char c = getchar (); for (; ! isdigit (c); c = getchar ()) if (c == '-' ) F = false ; int ret[pn]; for ( int i = 0; i < pn; i++) ret[i] = 0; for (; isdigit (c); c = getchar ()) for ( int i = 0; i < pn; i++) ret[i] = (ret[i] * 10 + c - '0' ) % p[i]; for ( int i = 0; i < pn; i++) a[i][x] = F ? ret[i] : p[i] - ret[i]; } int calculate( int x, int y) { int ret = 0; for ( int i = N; i; i--) ret = (ret + a[x][i]) * y % p[x]; if ((ret += a[x][0]) >= p[x]) ret -= p[x]; return ret; } int main() { scanf ( "%d%d" , &N, &M); for ( int i = 0; i <= N; i++) Read(i); for ( int i = 0; i < pn; i++) for ( int j = 0; j < p[i]; j++) f[i][j] = calculate(i, j); for ( int i = 1; i <= M; i++) { bool t = true ; for ( int j = 0; j < pn; j++) if (f[j][i % p[j]]) t = false ; if (t) ans[n++] = i; } printf ( "%d\n" , n); for ( int i = 0; i < n; i++) printf ( "%d\n" , ans[i]); return 0; } |
day2前2题依旧是简单, 第三题比较有难度
标签:
解题报告
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库