2020.09.06考试解题报告
总结
预计得分:\(100+(0\sim50)+100\)
实际得分:\(100+60+50\)
考试排名:\(4/7\)
\(T1\) 简单题,显然判断每一位就可以得到最优。
\(T2\) 只知道是个二分答案,但是不会 \(check\),然后交了一个连大样例都没过的代码上去得了 \(60\)。
\(T3\) 过了大样例就不管了,以为能对,然而少判断了一种情况。
大概有一个多小时的垃圾时间不知道自己在干嘛= =
我离成功就差那么亿点点/cy
题目分析
T1 咒语
显然可以分别判断每一位的 \(0/1\) 分布情况,输入 \(n\) 个字符串的同时记录每个字符串同一位上的 \(0/1\) 个数。
记 \(cnt0[i]\) 为第 \(i\) 位上 \(0\) 的个数, \(cnt1[i]\) 为第 \(i\) 位上 \(1\) 的个数。
当 \(cnt0[i]=cnt1[i]\) 时,选 \(0\) 和 \(1\) 的差异度相同,题目中保证 \(0\) 的个数最大,所以填 \(0\) 更优。
当 \(cnt0[i]>cnt1[i]\) 时,选 \(0\) 比选 \(1\) 更优,因为要保证差异度最小,因此填 \(0\)。
当 \(cnt0[i]<cnt1[i]\) 时,选 \(1\) 比选 \(0\) 更优,原因同上,因此填 \(1\)。
T2 神光
考场写了个假算法草了 \(60\) 分。
首先如果 \(R+G\ge N\) 直接输出 \(1\) 即可。
之后使用次数就缩小到了 \(2000\)。
容易想到二分答案判断 \(L\) 的长度,之后考虑如何 \(check\)。
要用到 \(\text{DP}\) 来做:
设 \(f[i][j]\) 表示用了 \(i\) 次红光, \(j\) 次绿光,能够从 \(1\) 开始解决到第几个法坛。
用 \(p[i]\) 表示从第 \(i\) 个法坛开始使用一次红光最多能覆盖到第几个法坛, \(q[i]\) 表示从第 \(i\) 个法坛开始使用一次绿光最多能覆盖到第几个法坛。
那么有\(f[i][j]=\max(p[f[i-1][j]+1],q[f[i][j-1]+1])\)
最后返回 \(f[r][g]\) 是否等于 \(n\) 即可(注意边界问题)
好简单的 \(\text{DP}\) 啊,为啥考试想不出来/kk
T3 迷宫
跑 \(\text{Dijkstra}\) 顺便记录所谓次短路即可过。
次短路就是比最短路要长的最小的路径,所以 \(\text{Dijkstra}\) 求最短路的同时找一找从每个点的最短路伸出的比最短路要大的最小路径,可以新开一个次短路数组专门记录这个次短路径 ,设当前节点为 \(x\),当前边连接的节点为 \(to\),\(w_{(x,to)}\) 表示边 \((x,to)\) 的权值\(,dis_{to}\) 表示 \(1\sim to\) 点的最短路,\(cdis_{to}\) 表示 \(1\sim to\) 点的次短路,则有以下三种情况:
-
\(dis_x+w_{(x,to)}\) 可以更新最短路 \(dis_{to}\)
这种情况先更新次短路为原最短路,然后用当前路径长度更新最短路。
-
\(dis_x+w_{(x,to)}\) 不能更新最短路,但是可以更新次短路
这种情况下说明 \(dis_x+w_{(x,to)}\) 不能作最短路,但是可以用于更新次短路,如果 \(cdis_{to}>dis_x+w_{(x,to)}\) 就可以更新次短路为 \(dis_x+w_{(x,to)}\)。
-
只能更新次短路(考试时忘记了这种情况)
也就是 \(cdis_{to} > cdis_x+w_{(x,to)}\) 的情况,此时可以更新次短路。
至于为什么不用 \(\text{SPFA}\),大家都懂(不过这道题并没有卡 \(\text{SPFA}\)
还有一种思路是直接跑最短路然后暴力 \(\text{DFS}\) 更新,具体思路如下:
题目要求次短路,我们可以先用 \(\text{Dijkstra}\) 算法求出最短路。设最短路长为 \(s_1\),与结点 \(n\) 相连的最短边的长度为 \(c\),设 \(s_2=s_1+2*c\), 则 \(s_2\) 就是次短路长度的上界。接下来我们只要进行 \(\text{DFS}\) 深搜即可,在搜索过程中利用上界 \(s_2\) 进行剪枝,并不断更新 \(s_2\),就可以在题目规定的时间内得到结果。
代码
T1
考场代码&&正解
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 2e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
char s[A];
int n, cnt0[A], cnt1[A], len;
int main() {
freopen("curse.in", "r", stdin);
freopen("curse.out", "w", stdout);
n = read();
for (int i = 1; i <= n; i++) {
scanf("%s", s + 1);
len = strlen(s + 1);
for (int j = 1; j <= len; j++) {
if (s[j] == '0') cnt0[j]++;
else cnt1[j]++;
}
}
for (int i = 1; i <= len; i++) {
if (cnt0[i] >= cnt1[i]) cout << 0;
else cout << 1;
}
puts("");
return 0;
}
T2
考场代码
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 2e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, r, g, a[A], maxn, ans;
inline bool check(int x) {
int re = x, gr = x * 2, cntr = 0, cntg = 0, pos = 1;
for (int i = 1; i <= n; i++) {
if (a[i + 1] - a[pos] + 1 <= re && cntr < r) {
while (a[i + 1] - a[pos] + 1 <= re) i++;
pos = i + 1, cntr++;
}
else if (a[i + 1] - a[pos] + 1 <= gr && cntg < g) {
while (a[i + 1] - a[pos] + 1 <= gr) i++;
pos = i + 1, cntg++;
}
else if (cntr < r) cntr++, pos = i + 1;
else if (cntg < g) cntg++, pos = i + 1;
else return false;
}
return cntr <= r && cntg <= g;
}
int main() {
freopen("light.in", "r", stdin);
freopen("light.out", "w", stdout);
n = read(), r = read(), g = read();
for (int i = 1; i <= n; i++) a[i] = read(), maxn = max(maxn, a[i]);
if (r + g >= n) return puts("1"), 0;
sort(a + 1, a + 1 + n);
int l = 1, r = maxn;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
cout << ans << '\n';
return 0;
}
正解
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 2e3 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, r, g, a[A], q[A], p[A], maxn, ans, f[A][A];
inline bool check(int x) {
int re = x, gr = 2 * x;
memset(f, 0, sizeof(f));
memset(q, 0, sizeof(q));
memset(p, 0, sizeof(p));
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
if (a[j] - a[i] + 1 <= re) p[i] = j;
if (a[j] - a[i] + 1 <= gr) q[i] = j;
}
}
p[n + 1] = q[n + 1] = n;
//这个必须要有,因为会用到边界+1的情况下,这时也应该是n
for (int i = 0; i <= r; i++)
for (int j = 0; j <= g; j++) {
if (i) f[i][j] = max(f[i][j], p[f[i - 1][j] + 1]);
if (j) f[i][j] = max(f[i][j], q[f[i][j - 1] + 1]);
}
return f[r][g] == n;
}
int main() {
n = read(), r = read(), g = read();
for (int i = 1; i <= n; i++) a[i] = read(), maxn = max(maxn, a[i]);
if (r + g >= n) return puts("1"), 0;
sort(a + 1, a + 1 + n);
int l = 1, r = maxn;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
cout << ans << '\n';
return 0;
}
T3
考场代码
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 2e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, head[A], cnt, dis[A], cdis[A];
struct Edge { int to, nxt, val; } e[A << 1];
inline void add(int from, int to, int val) {
e[++cnt].to = to;
e[cnt].val = val;
e[cnt].nxt = head[from];
head[from] = cnt;
}
struct node {
int x, y;
bool operator < (const node &b) const {
return y > b.y;
}
};
priority_queue <node> Q;
int main() {
freopen("maze.in", "r", stdin);
freopen("maze.out", "w", stdout);
n = read(), m = read();
for (int i = 1; i <= m; i++) {
int x = read(), y = read(), val = read();
add(x, y, val), add(y, x, val);
}
memset(dis, inf, sizeof(dis));
memset(cdis, inf, sizeof(cdis));
dis[1] = 0;
Q.push((node){1, 0});
while (!Q.empty()) {
int x = Q.top().x; Q.pop();
for (int i = head[x]; i; i = e[i].nxt) {
int to = e[i].to;
if (dis[to] >= dis[x] + e[i].val) {
dis[to] = dis[x] + e[i].val;
Q.push((node){to, dis[to]});
}
else if (cdis[to] > dis[x] + e[i].val) {
cdis[to] = dis[x] + e[i].val;
Q.push((node){to, cdis[to]});
}
}
}
cout << cdis[n] << '\n';
return 0;
}
正解
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 2e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, head[A], cnt, dis[A], cdis[A], vis[A];
struct Edge { int to, nxt, val; } e[A << 1];
inline void add(int from, int to, int val) {
e[++cnt].to = to;
e[cnt].val = val;
e[cnt].nxt = head[from];
head[from] = cnt;
}
struct node {
int x, y;
bool operator < (const node &b) const {
return y > b.y;
}
};
priority_queue <node> Q;
int main() {
// freopen("maze.in", "r", stdin);
// freopen("maze.out", "w", stdout);
n = read(), m = read();
for (int i = 1; i <= m; i++) {
int x = read(), y = read(), val = read();
add(x, y, val), add(y, x, val);
}
memset(cdis, inf, sizeof(dis));
memset(dis, inf, sizeof(dis));
dis[1] = 0;
Q.push((node) {1, 0});
while (!Q.empty()) {
int x = Q.top().x; Q.pop(); vis[x] = 0;
for (int i = head[x]; i; i = e[i].nxt) {
int to = e[i].to;
if (dis[to] > dis[x] + e[i].val) {
cdis[to] = dis[to];
dis[to] = dis[x] + e[i].val;
if (!vis[to]) vis[to] = 1, Q.push((node) {to, dis[to]});
}
if (dis[to] != dis[x] + e[i].val && cdis[to] > dis[x] + e[i].val) {
cdis[to] = dis[x] + e[i].val;
if (!vis[to]) vis[to] = 1, Q.push((node) {to, cdis[to]});
}
if (cdis[to] > cdis[x] + e[i].val) {
cdis[to] = cdis[x] + e[i].val;
if (!vis[to]) vis[to] = 1, Q.push((node) {to, cdis[to]});
}
}
}
cout << cdis[n] << '\n';
return 0;
}