20260724 - 暑期部分分训练 1

A - 方差

欸,正解是 SA?

24pts

爆搜就好了。

void dfs(const vector<int> &now) {  
    cnt.insert(now);  
    ll res = [&](const vector<int> &k) -> ll{  
        ll sqr = 0, sum = 0;  
        for (auto i : k) sqr += i * i, sum += i;  
        return n * sqr - sum * sum;  
    }(now);  
    ans = min(ans, res);  
    for (int i = 1; i < n - 1; i++) {  
        vector<int> t = now;  
        t[i] = t[i - 1] + t[i + 1] - t[i];  
        if (!cnt.count(t) || t[i] > ans)  
            dfs(t);  
    }  
}

32pts

如果答案比他大的多,就一定不行,设置一个分界点。

void dfs(const vector<int> &now, ll sqr, ll sum) {
    cnt[now] = true;
    ll res = n * sqr - sum * sum;
    if (res > 1.1 * ans) return;
    ans = min(ans, res);
    for (int i = 1; i < n - 1; i++) {
        vector<int> t = now;
        t[i] = t[i - 1] + t[i + 1] - t[i];
        if (cnt.find(t) == cnt.end()) {
            ll sq = sqr - now[i] * now[i] + t[i] * t[i], su = sum - now[i] + t[i];
            ll ret = n * sq - su * su;
            if (ret > 1.09 * ans) continue;
            dfs(t, sq, su);
        }
    }
}

正解是 SA?我要去学一下。

使用 A* 失败了。

B - 归程

30pts

跑一边 Dijkstra 就好了,注意有一个点 \(Q = 0\)?打 freopen 也能拿到 \(5pts\) 哈哈哈。

namespace sub1 {  
    void solve() {  
        dijkstra(1);  
        scanf("%d%d%d", &Q, &K, &S);  
        while (Q--) {  
            int v0, p0, v, h;  
            scanf("%d%d", &v0, &p0);  
            v = (v0 + K * lastans - 1) % n + 1;  
            h = (p0 + K * lastans) % (S + 1);  
            if (h < adj[1][0][2]) {  
                printf("%d\n", 0); lastans = 0;  
            } else {  
                lastans = dis[v];  
                printf("%d\n", dis[v]);  
            }  
        }  
    }  
};

55pts

因为树上路径唯一,所以直接树上倍增求最小值,然后判断是否能走,然后就没了。

namespace sub2 {  
    int fa[N][21], minv[N][21];  
    void dfs(int u, int from) {  
        for (auto nxt : adj[u]) {  
            int v = nxt[0], w = nxt[2];  
            if (v == from) continue;  
            fa[v][0] = u;  
            minv[v][0] = w;  
            dfs(v, u);  
        }  
    }  
    int getfa(int u, int t) {  
        if (!t) return 1;  
        for (int i = 20; i >= 0; i--) {  
            if (minv[u][i] > t) u = fa[u][i];  
        }  
        return u;  
    }  
    void solve() {  
        dfs(1, 0);  
        dijkstra(1);  
        for (int j = 1; j <= 20; j++) {  
            for (int i = 1; i <= n; i++) {  
                fa[i][j] = fa[fa[i][j - 1]][j - 1];  
                minv[i][j] = min(minv[i][j - 1], minv[fa[i][j - 1]][j - 1]);  
            }  
        }  
        scanf("%d%d%d", &Q, &K, &S);  
        while (Q--) {  
            int v0, p0, v, h;  
            scanf("%d%d", &v0, &p0);  
            v = (v0 + K * lastans - 1) % n + 1;  
            h = (p0 + K * lastans) % (S + 1);  
            lastans = dis[getfa(v, h)];  
            printf("%d\n", lastans);  
        }  
        for (int j = 1; j <= 20; j++) {  
            for (int i = 1; i <= n; i++) {  
                fa[i][j] = minv[i][j] = 0;  
            }  
        }  
    }  
};

70pts

从大到小排序,然后直接乱搞。

if (K == 0) {  
    dijkstra(1);  
    vector<int> ans(Q + 1);  
    vector<array<int, 3>> q;  
    for (int i = 1; i <= Q; i++) {  
        int v0, p0, v, h;  
        scanf("%d%d", &v0, &p0);  
        v = (v0 + K * lastans - 1) % n + 1;  
        h = (p0 + K * lastans) % (S + 1);  
        q.push_back({h, v, i});  
    }  
    sort(all(q), [&](const AR3 &A, const AR3 &B) {  
        return A[0] > B[0];  
    });  
    sort(all(edge), [&](const array<int, 4> &A, const array<int, 4> &B) {  
        return A[0] > B[0];  
    });  
    vector<int> fa(n + 1); iota(all(fa), 0);  
    auto find = [&](auto &self, int x) -> int {  
        if (fa[x] == x) return x;  
        return fa[x] = self(self, fa[x]);  
    };  
    auto merge = [&](int u, int v) -> void {  
        int uf = find(find, u), vf = find(find, v);  
        if (uf == vf) return;  
        if (dis[uf] < dis[vf]) fa[vf] = uf;  
        else fa[uf] = vf;  
    };  
    int idx = 0;  
    for (auto [h, v, id] : q) {  
        while (idx < m && h < edge[idx][0]) {  
            auto [a, x, y, l] = edge[idx];  
            merge(x, y);  
            ++idx;  
        }  
        ans[id] = dis[find(find, v)];  
    }  
    for (int i = 1; i <= Q; i++) printf("%d\n", ans[i]);  
}

80pts

直接爆搜就好了。

if (n <= 1500) {  
    dijkstra(1);  
    for (int i = 1; i <= Q; i++) {  
        int v0, p0, v, h;  
        scanf("%d%d", &v0, &p0);  
        v = (v0 + K * lastans - 1) % n + 1;  
        h = (p0 + K * lastans) % (S + 1);  
        vector<int> vis(n + 1); int ans = inf;  
        auto dfs = [&](auto &self, int u) -> void {  
            if (vis[u]) return;  
            vis[u] = true;  
            ans = min(ans, dis[u]);  
            for (auto [vc, l, a] : adj[u]) {  
                if (a > h) self(self, vc);  
            }  
        };  
        dfs(dfs, v);  
        printf("%d\n", lastans = ans);  
    }

完整奇葩码风代码:

#include <bits/stdc++.h>  
  
using namespace std;  
  
  
#define AKCoder  
  
#ifdef AKCoder  
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}  
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'  
#else  
#define debug(x);  
#endif  
  
#define ll long long  
#define ull unsigned long long  
#define db double  
#define all(x) (x).begin(), (x).end()  
#define inf (1 << 30)  
#define lnf (1LL << 60)  
typedef pair<int, int> PII;  
typedef array<int, 3> AR3;  
constexpr int N = 200000 + 7;  
constexpr int P = 998244353;  
  
int n, m;  
int Q, K, S, lastans;  
vector<array<int, 3>> adj[N];  
  
int dis[N];  
bool vis[N];  
  
void dijkstra(int s) {  
    priority_queue<AR3, vector<AR3>, greater<AR3>> q;  
    memset(dis, 0x3f, sizeof(dis));  
    memset(vis, false, sizeof(vis));  
    dis[s] = 0;  
    q.push({0, s});  
    while (!q.empty()) {  
        int u = q.top()[1]; q.pop();  
        if (vis[u]) continue; vis[u] = true;  
        for (auto nxt : adj[u]) {  
            int v = nxt[0], w = nxt[1];  
            if (dis[v] > dis[u] + w) {  
                dis[v] = dis[u] + w;  
                q.push({dis[v], v});  
            }  
        }  
    }  
}  
  
void clearT() {  
    lastans = 0;  
    for (int i = 1; i <= n; i++) adj[i].clear();  
}  
  
namespace sub1 {  
    void solve() {  
        dijkstra(1);  
        scanf("%d%d%d", &Q, &K, &S);  
        while (Q--) {  
            int v0, p0, v, h;  
            scanf("%d%d", &v0, &p0);  
            v = (v0 + K * lastans - 1) % n + 1;  
            h = (p0 + K * lastans) % (S + 1);  
            if (h < adj[1][0][2]) {  
                printf("%d\n", 0); lastans = 0;  
            } else {  
                lastans = dis[v];  
                printf("%d\n", dis[v]);  
            }  
        }  
    }  
};  
  
namespace sub2 {  
    int fa[N][21], minv[N][21];  
    void dfs(int u, int from) {  
        for (auto nxt : adj[u]) {  
            int v = nxt[0], w = nxt[2];  
            if (v == from) continue;  
            fa[v][0] = u;  
            minv[v][0] = w;  
            dfs(v, u);  
        }  
    }  
    int getfa(int u, int t) {  
        if (!t) return 1;  
        for (int i = 20; i >= 0; i--) {  
            if (minv[u][i] > t) u = fa[u][i];  
        }  
        return u;  
    }  
    void solve() {  
        dfs(1, 0);  
        dijkstra(1);  
        for (int j = 1; j <= 20; j++) {  
            for (int i = 1; i <= n; i++) {  
                fa[i][j] = fa[fa[i][j - 1]][j - 1];  
                minv[i][j] = min(minv[i][j - 1], minv[fa[i][j - 1]][j - 1]);  
            }  
        }  
        scanf("%d%d%d", &Q, &K, &S);  
        while (Q--) {  
            int v0, p0, v, h;  
            scanf("%d%d", &v0, &p0);  
            v = (v0 + K * lastans - 1) % n + 1;  
            h = (p0 + K * lastans) % (S + 1);  
            lastans = dis[getfa(v, h)];  
            printf("%d\n", lastans);  
        }  
        for (int j = 1; j <= 20; j++) {  
            for (int i = 1; i <= n; i++) {  
                fa[i][j] = minv[i][j] = 0;  
            }  
        }  
    }  
};  
  
void solve() {  
    bool markH = true;  
    int sameH = -1;  
    clearT();  
    scanf("%d%d", &n, &m);  
    vector<array<int, 4>> edge;  
    for (int i = 1; i <= m; i++) {  
        int u, v, l, a;  
        scanf("%d%d%d%d", &u, &v, &l, &a);  
        edge.push_back({a, u, v, l});  
        if (sameH == -1) sameH = a;  
        else if (sameH != a) markH = false;  
        adj[u].push_back({v, l, a});  
        adj[v].push_back({u, l, a});  
    }  
    if (markH) sub1::solve();  
    else if (n == m + 1) sub2::solve();  
    else {  
        scanf("%d%d%d", &Q, &K, &S);  
        if (K == 0) {  
            dijkstra(1);  
            vector<int> ans(Q + 1);  
            vector<array<int, 3>> q;  
            for (int i = 1; i <= Q; i++) {  
                int v0, p0, v, h;  
                scanf("%d%d", &v0, &p0);  
                v = (v0 + K * lastans - 1) % n + 1;  
                h = (p0 + K * lastans) % (S + 1);  
                q.push_back({h, v, i});  
            }  
            sort(all(q), [&](const AR3 &A, const AR3 &B) {  
                return A[0] > B[0];  
            });  
            sort(all(edge), [&](const array<int, 4> &A, const array<int, 4> &B) {  
                return A[0] > B[0];  
            });  
            vector<int> fa(n + 1); iota(all(fa), 0);  
            auto find = [&](auto &self, int x) -> int {  
                if (fa[x] == x) return x;  
                return fa[x] = self(self, fa[x]);  
            };  
            auto merge = [&](int u, int v) -> void {  
                int uf = find(find, u), vf = find(find, v);  
                if (uf == vf) return;  
                if (dis[uf] < dis[vf]) fa[vf] = uf;  
                else fa[uf] = vf;  
            };  
            int idx = 0;  
            for (auto [h, v, id] : q) {  
                while (idx < m && h < edge[idx][0]) {  
                    auto [a, x, y, l] = edge[idx];  
                    merge(x, y);  
                    ++idx;  
                }  
                ans[id] = dis[find(find, v)];  
            }  
            for (int i = 1; i <= Q; i++) printf("%d\n", ans[i]);  
        } else if (n <= 1500) {  
            dijkstra(1);  
            for (int i = 1; i <= Q; i++) {  
                int v0, p0, v, h;  
                scanf("%d%d", &v0, &p0);  
                v = (v0 + K * lastans - 1) % n + 1;  
                h = (p0 + K * lastans) % (S + 1);  
                vector<int> vis(n + 1); int ans = inf;  
                auto dfs = [&](auto &self, int u) -> void {  
                    if (vis[u]) return;  
                    vis[u] = true;  
                    ans = min(ans, dis[u]);  
                    for (auto [vc, l, a] : adj[u]) {  
                        if (a > h) self(self, vc);  
                    }  
                };  
                dfs(dfs, v);  
                printf("%d\n", lastans = ans);  
            }  
        }  
    }  
}  
  
int main() {  
    int oT_To = 1;  
    scanf("%d", &oT_To);  
    while (oT_To--) solve();  
    return 0;  
}

100pts

跑 Kruskal 重构树就好了。

#include <bits/stdc++.h>  
  
using namespace std;  
  
  
#define AKCoder  
  
#ifdef AKCoder  
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}  
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'  
#else  
#define debug(x);  
#endif  
  
#define ll long long  
#define ull unsigned long long  
#define db double  
#define all(x) (x).begin(), (x).end()  
#define inf (1 << 30)  
#define lnf (1LL << 60)  
typedef pair<int, int> PII;  
typedef array<int, 3> AR3;  
constexpr int N = 400000 + 7;  
constexpr int P = 998244353;  
  
struct Node {  
    int v, l, a;  
};  
  
struct Edge {  
    int u, v, l, a;  
    bool operator < (const Edge &A) const {  
        return a > A.a;  
    }  
};  
  
int n, m;  
int Q, K, S, lastans;  
vector<int> adj[N];  
vector<Node> graph[N];  
vector<Edge> edge;  
  
int dis[N];  
bool vis[N];  
  
void dijkstra(int s) {  
    priority_queue<AR3, vector<AR3>, greater<AR3>> q;  
    memset(dis, 0x3f, sizeof(dis));  
    memset(vis, false, sizeof(vis));  
    dis[s] = 0;  
    q.push({0, s});  
    while (!q.empty()) {  
        int u = q.top()[1]; q.pop();  
        if (vis[u]) continue; vis[u] = true;  
        for (auto [v, w, _] : graph[u]) {  
            if (dis[v] > dis[u] + w) {  
                dis[v] = dis[u] + w;  
                q.push({dis[v], v});  
            }  
        }  
    }  
}  
  
int fa[N], val[N], f[N][20], cnt, leaf[N];  
  
int find(int x) {  
    if (fa[x] == x) return x;  
    return fa[x] = find(fa[x]);  
}  
  
void ex_kruskal() {  
    sort(all(edge));  
    cnt = n;  
    for (int i = 1; i <= n * 2; i++) fa[i] = i;  
    for (auto [u, v, l, a] : edge) {  
        int uf = find(u), vf = find(v);  
        if (uf != vf) {  
            fa[uf] = fa[vf] = ++cnt;  
            val[cnt] = a;  
            adj[uf].push_back(cnt), adj[cnt].push_back(uf);  
            adj[vf].push_back(cnt), adj[cnt].push_back(vf);  
        }  
    }  
}  
  
void dfs(int u, int from) {  
    for (auto v : adj[u]) {  
        if (v == from) continue;  
        f[v][0] = u;  
        dfs(v, u);  
        leaf[u] = min(leaf[u], leaf[v]);  
    }  
    leaf[u] = min(leaf[u], dis[u]);  
}  
  
int half_lca(int u, int p) {  
    for (int i = 19; i >= 0; i--) {  
        if (val[f[u][i]] > p) u = f[u][i];  
    }  
    return u;  
}  
  
void clearT() {  
    cnt = 0;  
    lastans = 0;  
    edge.clear();  
    memset(leaf, 0x3f, sizeof(leaf));  
    for (int i = 1; i <= n * 2; i++) adj[i].clear(), graph[i].clear();  
}  
  
void solve() {  
    clearT();  
    scanf("%d%d", &n, &m);  
    for (int i = 1; i <= m; i++) {  
        int u, v, l, a;  
        scanf("%d%d%d%d", &u, &v, &l, &a);  
        graph[u].push_back({v, l, a});  
        graph[v].push_back({u, l, a});  
        edge.push_back({u, v, l, a});  
    }  
    dijkstra(1);  
    ex_kruskal();  
    dfs(cnt, 0);  
    for (int j = 1; j <= 19; j++)  
        for (int i = 1; i <= cnt; i++)  
            f[i][j] = f[f[i][j - 1]][j - 1];  
    scanf("%d%d%d", &Q, &K, &S);  
    while (Q--) {  
        int v0, p0, v, h;  
        scanf("%d%d", &v0, &p0);  
        v = (v0 + K * lastans - 1) % n + 1;  
        h = (p0 + K * lastans) % (S + 1);  
        int pos = half_lca(v, h);  
        printf("%d\n", lastans = leaf[pos]);  
    }  
}  
  
int main() {  
    // freopen("return.out", "w", stdout);  
    int oT_To = 1;  
    scanf("%d", &oT_To);  
    while (oT_To--) solve();  
    return 0;  
}

多测不清空,爆零两行泪!!!

posted @ 2026-07-24 22:25  AKCoder  阅读(18)  评论(0)    收藏  举报