LGP2865 USACO06NOV Roadblocks G
分析
我感觉可以动态维护次大值......做完了......
不是哥们,你别乱写 Dijkstra 啊!
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 5005;
int n, r;
vector<pair<int, int>> e[N];
int d[N], dd[N];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
void dijkstra(int S){
memset(d, 0x3f, sizeof(d));
memset(dd, 0x3f, sizeof(dd));
d[S] = 0;
q.push({0, S});
while (!q.empty()){
auto tmp1 = q.top();
q.pop();
int du = tmp1.first;
int u = tmp1.second;
if (du > dd[u])
continue;
for (auto tmp2 : e[u]){
int v = tmp2.first;
int w = tmp2.second;
int nd = du + w;
if (nd < d[v]){
dd[v] = d[v];
d[v] = nd;
q.push({d[v], v});
if (dd[v] < 0x3f3f3f3f)
q.push({dd[v], v});
}
else if (nd > d[v] && nd < dd[v]){
dd[v] = nd;
q.push({dd[v], v});
}
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> r;
for (int i = 1, a, b, d; i <= r; i++){
cin >> a >> b >> d;
e[a].push_back({b, d});
e[b].push_back({a, d});
}
dijkstra(1);
cout << dd[n];
}
LGP2868 USACO07DEC Sightseeing Cows G
原题链接:USACO07DEC Sightseeing Cows G
分析
别急,这个就是给我写 O ( n 2 ) O(n^2) O(n2) 的?
那不就是你开一个超级源点,Dijkstra 的时候算路径的最小时间和最大点权,然后,枚举,找一个最大值就行了?
竟然是最大比率环?那我不会了。
别急,我居然看过这集吗?我好像暑假真的学过......那不就是二分吗?
哦,妙哉妙哉!
那么,开写吧......
正解
cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, M = 5005;
const double eps = 1e-6;
int l, p, f[N];
struct edge{
int to, nxt, w;
}e[M];
int head[N], tot;
bool vis[N];
int cnt[N];
double d[N];
void add(int u, int v, int w){
e[++tot].nxt = head[u];
e[tot].to = v;
e[tot].w = w;
head[u] = tot;
}
bool check(double x){
queue<int> q;
for (int i = 1; i <= l; i++){
q.push(i);
d[i] = 0;
vis[i] = true;
cnt[i] = 1;
}
while (!q.empty()){
int u = q.front();
q.pop();
vis[u] = false;
for (int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
double val = e[i].w;
if (d[v] > d[u] + x * val - f[u]){
d[v] = d[u] + x * val - f[u];
if (!vis[v]){
q.push(v);
vis[v] = true;
if (++cnt[v] >= l)
return true;
}
}
}
}
return false;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> l >> p;
for (int i = 1; i <= l; i++){
cin >> f[i];
}
for (int i = 1, l1, l2, t; i <= p; i++){
cin >> l1 >> l2 >> t;
add(l1, l2, t);
}
double L = 0, R = 1000000;
while (R - L > eps){
double mid = (L + R) / 2.0;
if (check(mid))
L = mid;
else
R = mid;
}
cout << fixed << setprecision(2) << L;
}
AT_abc478_f ABC478F Min-First Search
分析
这为啥是绿啊😭
道心破碎了😭
l r h lrh lrh 咋这么牛拜谢
确实,你会发现这个东西类似于 dfn,同时,又加上了每次选取最小值这一条件。
这么一看,这道题不是特别困难......但是,也并不简单......为啥我场上没有想这道题啊😭

不可以吗?
别急,那不就是先后出现的问题吗?那不是随便做吗?
哦,那不就是前面的都有可能成为它的父亲,然后乘一下,做完了?
说得有点笼统。
那不就是如果前面出现了比这个数更大的数,那么,他肯定在这个数之前,是这个位置的祖先,同样,在这一段上升之中,还是有可能作为这个位置的祖先,那么,个数乘起来不就行了?
正解
cpp
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 200005;
int n, q[N];
int pre[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 0; i < n; i++){
cin >> q[i];
q[i]--;
}
int ans = 1;
for (int i = 1; i < n; i++){
int pos = i - 1;
while (pos > 0 && q[pos] < q[i]){
pos = pre[pos];
}
pre[i] = pos;
ans = ans * (i - pos) % mod;
}
cout << ans;
}