第二节 杂题练习 (草稿版)

总述

一些奇怪的题,放了好久都还没做,自己做做看对应知识点需不需要补。

天路

感觉自从做了二分以后好板子。分式直接化整式就做完了啊。

设 \(\dfrac{\sum_{i=1}^{m} V_i}{\sum_{i=1}^m P_i} = T\),则 \(T\sum_{i=1}^m P_i = \sum_{i=1}^m V_i\),即 \(\sum_{i=1}^m TP_i = \sum_{i=1}^m V_i\),得 \(\sum_{i=1}^m (TP_i - V_i) = 0\)。设 \(W_i = TP_i - V_i\),则答案为使得 \(\sum_{i=1}^m W_i \ge 0\) 的最小 \(T\)。

要达成该目标,判负环就完事了啊。这道题要用 DFS 版的 SPFA。

负环怎么判,BFS 里如果一个点被过了 \(n\) 次直接挂,DFS 里成环就退出。

然后就做完了。

bool spfa(int u, double T){
    vis[u] = true;
    for (edge g : e[u]){
        int v = g.v; double t = g.t * T - g.f;
        if (dis[u] + t >= dis[v]) continue;
        if (vis[v]) { vis[u] = false; return false; }
        dis[v] = dis[u] + t;
        if (!spfa(v, T)) { vis[u] = false; return false; }
    }
    vis[u] = false;
    return true;
}

序列

不太明白这道题差分约束在哪,我只看出来能贪心了。

按右端点排序,显然收益最大。所有的点都尽量往右边放就行了。

[USACO05DEC] Layout G

差分约束,本来想在台上给他们讲来着。这下的话算了吧。

差分约束,形如若干个 \(p_u - p_v \ge t\),变形得到 \(p_u \ge p_v + t\),也就是最段路的松弛。

故 \((v, u) \to t\) 跑最短路即可,这道题其实非常模板。

提示一下如果 \(p_u - p_v \le t\),变形可得 \(p_v \ge p_u + (-t)\)。

值得注意的是题目需要两遍 spfa,第一遍从超级原点判负环第二遍算答案。

[USACO13JAN] Square Overlap S

没招了先把俩轴拆了。考虑题目本质上限制了重合的正方形只可能有一对,如果出现第二对直接就挂掉,所以不重合的正方形的 \(l, r\) 在 set 中应该是依次出现的。

嘶,注意到重合是没办法处理的。考虑每个正方形本质上是边长相等的,故其相交的条件是中心点在两个轴的坐标差小于 \(k\)。

此时显然可以认为在对图形进行操作。先将所有点按 \(x\) 轴排序,然后检查插入位置相邻点即可。

细节还是不少的。

#include <bits/stdc++.h>
using namespace std;

const int N = 5e4 + 5;
int n, k;
long long ans;
pair<int, int> a[N];
set<pair<int, int>> s;

int main(){
    cin >> n >> k;
    for (int i = 1; i <= n; i++){
        cin >> a[i].first >> a[i].second;
    }
    sort(a+1, a+n+1);
    for (int i = 1, j = 1; i <= n; i++){
        while (j < i && a[i].first - a[j].first >= k){
            s.erase({a[j].second, j});
            j++;
        }
        set<pair<int, int>>::iterator itl = s.insert({a[i].second, i}).first, itr = itl;
        if (itl-- != s.begin() && a[i].second - itl->first < k){
            if (!ans) ans = 1ll * (k - (a[i].first - a[itl->second].first)) * (k - (a[i].second - itl->first));
            else ans = -1;
        }
        if (++itr != s.end() && itr->first - a[i].second < k){
            if (!ans) ans = 1ll * (k - (a[i].first - a[itr->second].first)) * (k - (itr->first - a[i].second));
            else ans = -1;
        }
    }
    cout << ans << endl;
    return 0;
}

[COCI 2020/2021 #5] Po

看起来有点板子了。考虑一个区间能够扩充的尽量长肯定相对更优,但是对于前面的一个高度如果这个位置不够加就要弹出。

直接设计一个单调栈即可,怎么这种水黄还在我的题单里。

机器分配

水题,看到题想不起来背包的可以回家睡觉了。

背包板子,考虑额外最小化一下状态即可。

posted @ 2026-09-14 15:53  _lhr  阅读(3)  评论(0)    收藏  举报