10.19 模拟赛题解报告
作者:互联网
写在前面
得分情况:\(100 + 100 + 10\)
(次短路板子忘了怎么写的大蒟蒻 = =
T1
直接贪心看每一位 \(0\) 多还是 \(1\) 多就好了。
/*
work by: Ariel_
Knowledge:
Time:
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = 1e3 + 5;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int n;
char s[MAXN];
struct node{int cnt_0, cnt_1;}cnt[MAXN];
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);
int len = strlen(s + 1);
for (int j = 1; j <= len; j++) {
if(s[j] == '0') cnt[j].cnt_0++;
else cnt[j].cnt_1++;
}
}
int len = strlen(s + 1);
for (int i = 1; i <= len; i++) {
if(cnt[i].cnt_0 >= cnt[i].cnt_1) putchar('0');
else putchar('1');
}
return 0;
}
T2
很显然要二分这个 \(L\),关键是如何写 \(check\)。
首先发现 \(G\) 和 \(R\) 的范围很大,但 \(n\) 的范围很小。
再想一下,其实当 \(G + R \geq n\) 的时候,\(L\) 就可以设为 \(1\),这样就将 \(G, R\) 的范围缩小到了 \(2000\) 以内。
考虑 \(dp\) 判断:
算法一
设 \(f_{i, j}\) 用了 \(i\) 次红光,用了 \(j\) 次绿光向右扩展到的最远的法坛。
预处理 \(p_i\) 表示从 \(i\) 点用红光能向右能扩展到最远的是哪个法坛,\(q_i\)表示从 \(i\) 点用绿光向右能扩展到最远的是哪个法坛。
\(f_{i, j} = \max\{p[f_{i - 1, j}+1], q[f_{i, j - 1}+1]\}\)
code
/*
work by: Ariel_
Knowledge:
Time:
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int n, R, G, a[MAXN], Ans, f[2010][2010];
bool Check(int L) {
for (int i = 1; i <= n; i++)
for (int j = 0; j <= R; j++) f[i][j] = INF;
int l1 = 0, l2 = 0;
f[0][0] = 0;
for (int i = 1; i <= n; i++){
while(l1 < n && a[l1 + 1] + L <= a[i]) l1++;
while(l2 < n && a[l2 + 1] + 2 * L <= a[i]) l2++;
for (int j = 0; j <= R; j++) {
if(j) f[i][j] = min(f[i][j], f[l1][j - 1]);
f[i][j] = min(f[i][j], f[l2][j] + 1);
}
}
for(int i = 0; i <= R; ++i) if(f[n][i] <= G) return true;
return false;
}
int main(){
n = read(), R = read(), G = read();
if(R + G >= n) {puts("1"); return 0;}
for (int i = 1; i <= n; i++) a[i] = read();
sort(a + 1, a + n + 1);
int l = 1, r = 1e9, Ans = r;
while(l <= r) {
int mid = (l + r) >> 1;
if(Check(mid)) Ans = mid, r = mid - 1;
else l = mid + 1;
}
cout<<Ans;
return 0;
}
算法二
\(f_{i, j}\) 表示用了 \(j\) 次红光,摧毁前 \(i\) 个位置的法坛,用的绿光的最少次数。
\(l1\) 是上一次使用红光的位置,\(l2\) 是上一次使用绿光的位置
转移:
\[f_{i, j} = \min\{f_{l_1, j - 1, }, f_{l_2, j} + 1\} \]\(l_1\) 和 \(l_2\) 可以用双指针维护。
复杂度 \(O(n^2logn)\)
code
/*
work by: Ariel_
Knowledge:
Time:
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int n, R, G, a[MAXN], Ans, f[2010][2010];
bool Check(int L) {
for (int i = 1; i <= n; i++)
for (int j = 0; j <= R; j++) f[i][j] = INF;
int l1 = 0, l2 = 0;
f[0][0] = 0;
for (int i = 1; i <= n; i++){
while(l1 < n && a[l1 + 1] + L <= a[i]) l1++;
while(l2 < n && a[l2 + 1] + 2 * L <= a[i]) l2++;
for (int j = 0; j <= R; j++) {
if(j) f[i][j] = min(f[i][j], f[l1][j - 1]);
f[i][j] = min(f[i][j], f[l2][j] + 1);
}
}
for(int i = 0; i <= R; ++i) if(f[n][i] <= G) return true;
return false;
}
int main(){
n = read(), R = read(), G = read();
if(R + G >= n) {puts("1"); return 0;}
for (int i = 1; i <= n; i++) a[i] = read();
sort(a + 1, a + n + 1);
int l = 1, r = 1e9, Ans = r;
while(l <= r) {
int mid = (l + r) >> 1;
if(Check(mid)) Ans = mid, r = mid - 1;
else l = mid + 1;
}
cout<<Ans;
return 0;
}
T3
次短路板子题
两种做法:
算法一
对每个点记录一个到达这个点的最短路和次短路。
考虑什么时候能更新最短路,什么时候能更新次短路。
特判考虑全(1:1, 2:1, 2:2)
code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN = 5010, MAXM = 200010;
int read() {
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
return x * f;
}
int n, m, dis[MAXN][3], vis[MAXN];
struct edge{int v, nxt, w;}e[MAXM << 1];
int E, head[MAXN];
void add_edge(int u, int v, int w) {
e[++E] = (edge){v, head[u], w};
head[u] = E;
}
queue<int>q;
void Spfa(int s){
memset(dis, 0x3f, sizeof dis);
memset(vis, false, sizeof vis);
q.push(1), dis[1][1] = 0;
while(!q.empty()){
int u = q.front();
q.pop(), vis[u]=0;
for(int i = head[u];i;i=e[i].nxt){
int v = e[i].v;
if(dis[v][1] > dis[u][1] + e[i].w){
dis[v][2] = dis[v][1];
dis[v][1] = dis[u][1] + e[i].w;
if(!vis[v]) q.push(v), vis[v] = 1;
}
if(dis[v][2] > dis[u][2] + e[i].w){
dis[v][2] = dis[u][2] + e[i].w;
if(!vis[v]) q.push(v), vis[v] = 1;
}
if(dis[v][2] > dis[u][1] + e[i].w && dis[v][1] < dis[u][1] + e[i].w){
dis[v][2] = dis[u][1] + e[i].w;
if(!vis[v]) q.push(v), vis[v] = 1;
}
}
}
}
int main() {
n = read(), m = read();
for (int i = 1, u, v, w; i <= m; i++) {
u = read(), v = read(), w = read();
add_edge(u, v, w), add_edge(v, u, w);
}
Spfa(1);
printf("%d", dis[n][2]);
system("pause");
return 0;
}
标签:int,题解,10.19,vis,while,getchar,include,模拟,dis 来源: https://www.cnblogs.com/Arielzz/p/15427248.html