E.Don’t Really Like How The Story Ends
参考题解
思路
举例:从 1 1 1 开始出发,接下来连接的点要遍历的是 2 2 2,那么接下来的几种情况是
- ( 2 , 3 ) (2, 3) (2,3) 存在
- ( 2 , 3 ) (2, 3) (2,3) 不存在,但是 2 2 2 之后没有点和 2 2 2 相连,那么这个节点就没必要遍历了,加上 3 3 3 并不会使结果变好,如果 ( 1 , 3 ) (1,3) (1,3) 存在,那么回溯到 1 1 1,结果最优,如果不存在到时候再说
- ( 2 , 3 ) (2, 3) (2,3) 不存在,但是 2 2 2 之后有点和 2 2 2 相连,比如有 ( 2 , 4 ) (2,4) (2,4),那么必须把 3 3 3 加入,否则就到了 4 4 4
细节解释
- 注释1:
- 注释2:
- 注释3:
- 注释4:
- 注释5:
- 注释6:
- 注释7:
- 注释8:
AC(dfs)
#include <bits/stdc++.h>
using namespace std;
#define PB push_back
typedef vector<int> VI;
const int N = 1e5 + 10;
int n, m, ne, ans;
VI edge[N];
void dfs(int e) {
if (e == n + 1) return; //注释1
for (auto x : edge[e]) { //注释2
while (x >= ne) //注释13
if (x == ne) { //注释4
ne ++;
dfs(ne - 1);
} else if (x > ne) { //注释5
ne ++;
ans ++;
dfs(ne - 1);
}
}
}
int main() {
int t;
scanf("%d", &t);
while (t -- ) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i ++ ) {
int u, v;
scanf("%d%d", &u, &v);
edge[u].PB(v), edge[v].PB(u);
}
ne = 2, ans = 0; //注释6
edge[1].PB(n + 1); //注释7
for (int i = 1; i <= n; i ++ )
sort(edge[i].begin(), edge[i].end()); //注释8
dfs(1);
cout << ans << endl;
for (int i = 1; i <= n; i ++ ) edge[i].clear();
}
return 0;
}
L. Spicy Restaurant
参考博客
时间复杂度
O ( 100 ∗ ( n + m ) ) O(100 * (n + m) ) O(100∗(n+m))
思路
- w [ i ] < 100 w[i] < 100 w[i]<100提示
- 一开始我的思路是在考虑要不要就直接每个点 b f s bfs bfs,算了一下复杂度是 O ( 100 n 2 ) O(100n ^ 2) O(100n2),显然不对,所以就否定了该想法
- 那么考虑多源 b f s bfs bfs ,时间复杂度就可以降低到 O ( 100 ( n + m ) ) O(100(n + m)) O(100(n+m))
- 分析时间复杂度:注释1和2就是 100 n 100 n 100n,注释3和4就是 100 m 100m 100m
- d i s t [ i ] [ j ] dist[i][j] dist[i][j]含义: j j j 是辣度, i i i 是餐馆
细节解释
- 注释1:对于辣度等于 a a a 的餐馆放入 t m p tmp tmp 队列中
- 注释2:并且这个辣度这个餐馆是可以不移动的,即 d i s t [ i ] [ j ] dist[i][j] dist[i][j] 是 0 0 0
- 注释3:如果 x x x 餐馆的 a a a 辣度没有被更新过,那么就把他放入 t m p tmp tmp 队列里
- 注释4: 防止反复,所以取 m i n min min,也就是找到目前这个点 d i s t [ t ] [ a ] dist[t][a] dist[t][a] 转移到 d i s t [ x ] [ a ] dist[x][a] dist[x][a] 近,还是 d i s t [ x ] [ a ] dist[x][a] dist[x][a]本身就很近
- 注释5: w [ i ] < 100 w[i] < 100 w[i]<100提示
- 注释6:因为在某些辣度 a a a 并没有餐馆
总结
- 第一次被
cin
和cout
坑
AC(bfs)
#include <bits/stdc++.h>
using namespace std;
#define PB push_back
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
int n, m, q;
int w[N];
int dist[N][110];
VI edge[N];
void bfs(int a) {
queue<int> tmp;
for (int i = 1; i <= n; i ++ )
if (w[i] == a) {
tmp.push(i); //注释1
dist[i][a] = 0; //注释2
}
while (!tmp.empty()) {
int t = tmp.front();
tmp.pop();
for (auto x : edge[t]) {
if (dist[x][a] == INF) tmp.push(x); //注释3
dist[x][a] = min(dist[x][a], dist[t][a] + 1); //注释4
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &q);
memset(dist, 0x3f, sizeof dist);
for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
for (int i = 1; i <= m; i ++ ) {
int u, v;
scanf("%d%d", &u, &v);
edge[u].PB(v), edge[v].PB(u);
}
for (int i = 1; i <= 100; i ++ ) bfs(i); //注释5
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= 100; j ++ )
dist[i][j] = min(dist[i][j], dist[i][j - 1]);
} //注释6
for (int i = 1; i <= q; i ++ ) {
int q, a;
scanf("%d%d", &q, &a);
if (dist[q][a] == INF) printf("-1\n");
else printf("%d\n", dist[q][a]);
}
return 0;
}
J.Ants
思路
- t l tl tl 以左为出口的尾位置, t r tr tr 以右为出口的尾位置, h l hl hl 以左为出口的头位置, h r hr hr 以右为出口的头位置, l l l 就是左为出口的蚂蚁队列, r r r 就是右为出口的蚂蚁队列, t m p tmp tmp 最后一轮,蚂蚁所需要的时间
- 对于前面的轮次,我们可以直接忽略,我们只要考虑最后一次蚂蚁怎么出去就可以了,把前面的轮次减去,我们可以保证会在下一轮全部出去
细节注释
- 注释1:对于前面的轮次,我们可以直接忽略,我们只要考虑最后一轮蚂蚁怎么出去就可以了
- 注释2:两个障碍物的坚硬度减去轮数,注意此时不一定存在 A = = 0 A == 0 A==0 或 B = = 0 B == 0 B==0
- 注释3:题干中 a [ i ] < a [ i + 1 ] a[i] < a[i + 1] a[i]<a[i+1],所以对于左边是正序,右边是逆序,对于右来说 a [ i ] a[i] a[i] 越大,他离右端点越近。为什么一定是顺序来,因为蚂蚁撞障碍物有先后顺序
- 注释4:左右队列只要不是空,因为就是说,还有蚂蚁没出去
- 注释5:右边的蚂蚁走完了,或者是左边右边都没走完并且左边的蚂蚁比右边的蚂蚁先撞障碍物,另一种情况就是左边走完了,或者左右都没走完并且右边的蚂蚁比左边先撞障碍物
- 注释6:在注释5条件下,取出当前最快撞障碍物的蚂蚁,和 t m p tmp tmp 比,防止这是一个从左边出去的蚂蚁
- 注释7:只要左边的障碍物坚硬度不为 0 0 0,就意为着,左边的蚂蚁会撞他,并从右边出去,所以我们要把他加入右边蚂蚁的队列,为什么是 u + m o d u + mod u+mod,对于右就是 l [ i ] + m o d l[i] + mod l[i]+mod,把左转化成右
AC(bf)
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 1;
const int N = 2e6 + 10;
LL l[N], r[N], a[N];
int d[N];
int hl, hr, tl, tr;
LL tmp, A, B;
void judge1() {
LL u = l[++ hl]; //注释6
tmp = max(tmp, u);
if (A) { //注释7
A --; //注释7
r[++ tr] = u + mod; //注释7
}
}
void judge2() {
LL u = r[++ hr];
tmp = max(tmp, u);
if (B) {
B --;
l[++ tl] = u + mod;
}
}
int main() {
int n;
scanf("%d%lld%lld", &n, &A, &B);
for (int i = 1; i <= n; i ++ ) scanf("%lld", a + i);
for (int i = 1; i <= n; i ++ ) scanf("%d", d + i);
LL lun = min(A / (LL)n, B / (LL)n); //注释1
LL ans = 1ll * lun * mod * 2;
A -= lun * n, B -= lun * n; //注释2
for (int i = 1; i <= n; i ++ )
if (d[i] == 0) l[++ tl] = a[i]; //注释3
for (int i = n; i >= 1; i -- )
if (d[i]) r[++ tr] = mod - a[i]; //注释3
while (hl < tl || hr < tr) { //注释4
if (hr >= tr || (hl < tl && l[hl] < r[hr])) judge1(); //注释5
else judge2();
}
printf("%lld\n", tmp + ans);
return 0;
}