首页 > 其他分享 >ABC364题解(D-G)

ABC364题解(D-G)

时间:2024-07-27 23:07:04浏览次数:14  
标签:连通 min int 题解 ll cin long ABC364

D

先对 \(a\) 从小到大排序。

将题目转化成找到最小的 \(d\),使得恰好有 \(k\) 个 \(a_i\in [b-d,b+d]\)。

对于每个询问 \(b,k\),考虑二分答案。

设待检查的答案为 \(d\),二分找到最小的 \(p1\) 使得 \(a_{p1}\geq b-d\) 和最小的 \(p2\) 使得 \(a_{p2}> b+d\),包含的数的个数即为 \(p2-p1\)。

  • 如果 \(p2-p1\ge k\),\(r\gets mid\)。
  • 否则,\(l\gets mid+1\)。

答案即为 \(r\)。

时间复杂度 \(O(n\log^2n)\)。

E

考虑 dp 求解。

设 \(f(i,j,k)\) 表示 dp 到第 \(i\) 道菜,吃了 \(j\) 盘,总甜度为 \(k\) 时总咸度的最小值。

于是有转移:

\(f(i,j,k)=\min\left(f(i-1,j,k),f(i-1,j-1,k-a_i)+b_i\right)\)。

答案是多少?

注意到最后一道菜随便吃,所以找到最大的 \(j\),使得存在 \(k\in[0,x]\) 满足 \(f(n,j,k)\leq y\)(先满足要求),答案即为 \(\min(j+1,n)\)(最后随便吃)。

如果找不到,答案就是 \(0\)。

复杂度 \(O(n^2V)\)。

F

考虑 kruskal 算法求最小生成树的思想:贪心从小到大选边,如果一条边两端在同一连通块内就不加入图中,否则加入。

注意到 \(n+i\) 号点相当于联通了 \([l_i,r_i]\) 中的所有点,但是暴力加边不可取,可以考虑并查集维护连通块。

具体的,\(n\) 个点所属并查集的根节点代表连通块右端点,合并两个连通块即为把 左侧连通块根节点的父亲 变为 右侧连通块的根节点。

这样我们就可以快速跳过连通块中间部分,快速找到两个连通块的连接处,然后加边。

所以把 \(>n\) 的点按照 \(c_i\) 排序,连接时从 \(l_i\) 所属连通块开始连接,直到 \(r_i\) 和所属连通块联通即可。答案即为连接的连通块数量。

复杂度线性。

G

\(k\) 这么小,直接考虑状压 dp。

设 \(f(i,s)\) 表示考虑到点 \(i\),\(i\) 和集合 \(s\) 中的点通过修过的路联通的最小代价。

于是有转移:

\(f(i,s)=\min_{u\in s}\left(\min_{(i,j)\in edge}f(j,u)+w(i,j)+\min_{(i,j)\in edge}f(j,s-u)+w(i,j)\right)\)

这样的复杂度是 \(O(n^23^n)\) 的,无法通过。

但是可以考虑设 \(g(i,s)=\min_{(i,j)\in edge}f(j,s)+w(i,j)\)。

这样,转移方程变为:

\(f(i,s)=\min_{u\in s}\left(g(i,u)+g(i,s-u)\right)\)
\(g(i,s)=\min_{(i,j)\in edge}f(j,s)+w(i,j)\)

注意到 \(f(i,s)\) 依赖于 \(s\) 的子集,所以先从小到大枚举 \(s\),再枚举 \(i\)。

但是转移方成立有同层(同样的\(s\))之间的转移?

注意到 \(g\) 的转移像是最短路,可以用最短路进行同层的转移。

复杂度 \(O(n3^n+m2^n+m2^n\log m)\)。


D

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

const int N = 1e5 + 5;
int a[N], n, q;

int chk(int b, int k, int d)
{
    int p1 = lower_bound(a + 1, a + n + 1, b - d) - a;
    int p2 = upper_bound(a + 1, a + n + 1, b + d) - a - 1;
    return p2 - p1 + 1;
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n >> q;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    sort(a + 1, a + n + 1);
    while(q --)
    {
        int b, k; cin >> b >> k;
        int l = 0, r = 2e8;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(chk(b, k, mid) >= k) r = mid;
            else l = mid + 1;
        }
        cout << r << "\n";
    }

    return 0;
}

E

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

const int N = 85, M = 1e4 + 5;
ll f[N][N][M], n, a[N], b[N], x, y;

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n >> x >> y;
    for(int i = 1; i <= n; i ++) cin >> a[i] >> b[i];
    memset(f, 0x3f, sizeof f);
    f[0][0][0] = 0;
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 0; j <= i; j ++)
        {
            for(int k = 0; k <= x; k ++)
            {
                f[i][j][k] = min(f[i][j][k], f[i - 1][j][k]);
                if(k - a[i] >= 0 && j && f[i - 1][j - 1][k - a[i]] + b[i] <= y) f[i][j][k] = min(f[i][j][k], f[i - 1][j - 1][k - a[i]] + b[i]);
            }
        }
    }
    for(int i = n; i >= 0; i --)
    {
        for(int j = 0; j <= x; j ++)
        {
            if(f[n][i][j] <= y)
                return cout << min(n, (ll)i + 1) << "\n", 0;
        }
    }
    cout << 0;

    return 0;
}

F

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

const int N = 2e5 + 5;
int n, q, fa[N];
struct node {int l, r, v;} a[N];

int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n >> q;
    for(int i = 1; i <= n; i ++) fa[i] = i;
    for(int i = 1; i <= q; i ++) cin >> a[i].l >> a[i].r >> a[i].v;
    sort(a + 1, a + q + 1, [](node &x, node &y) {return x.v < y.v;});
    ll ans = 0;
    for(int i = 1; i <= q; i ++)
    {
        int u = find(a[i].l), ed = find(a[i].r);
        ans += a[i].v;
        while(u != ed) fa[u] = find(u + 1), u = find(u), ans += a[i].v;
    }
    if(find(1) != n) cout << -1, 0;
    else cout << ans;

    return 0;
}

G

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

const int N = 4e3 + 5, K = 9;
ll f[N][1 << K], mn[N][1 << K];
int n, m, k;
vector<pair<int, ll>> e[N];

void spread(int j)
{
    static bool vis[N + 5] = {};
    memset(vis, 0, sizeof vis);
    using pii = pair<ll, int>;
    priority_queue<pii, vector<pii>, greater<pii>> q;
    for(int i = 1; i <= n; i ++) q.push({f[i][j], i});
    while(q.size())
    {
        int t = q.top().second; q.pop();
        if(vis[t]) continue;
        vis[t] = 1;
        for(auto [i, w] : e[t])
        {
            if(f[i][j] > f[t][j] + w)
            {
                f[i][j] = f[t][j] + w;
                if(!vis[i]) q.push({f[i][j], i});
            }
        }
    }
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n >> m >> k;
    for(int i = 1; i <= m; i ++)
    {
        int x, y, z; cin >> x >> y >> z;
        e[x].push_back({y, z});
        e[y].push_back({x, z});
    }
    for(int i = 1; i <= n; i ++) e[i].push_back({i, 0});
    memset(f, 0x3e, sizeof f);
    for(int i = 1; i < k; i ++)
        f[i][1 << i - 1] = 0;
    ll ans = 1e18;
    memset(mn, 0x3e, sizeof mn);
    for(int i = 1; i <= n; i ++) mn[i][0] = 0;
    for(int j = 0; j < (1 << k - 1); j ++)
    {
        for(int i = 1; i <= n; i ++)
        for(int s = j; s; s = (s - 1) & j)
            f[i][j] = min(f[i][j], mn[i][s] + mn[i][j ^ s]);
        spread(j);
        for(int i = 1; i <= n; i ++)
            for(auto [u, w] : e[i])
                mn[u][j] = min(mn[u][j], f[i][j] + w);
    }
    for(int i = k; i <= n; i ++) cout << f[i][(1 << k - 1) - 1] << "\n";

    return 0;
}

标签:连通,min,int,题解,ll,cin,long,ABC364
From: https://www.cnblogs.com/adam01/p/18327669

相关文章

  • 题解:P10481 Sudoku
    Sudoku来自蓝书思路优化搜索顺序,位运算常数优化。优化搜索顺序数独问题的搜索很简单,“搜索状态”就是每个位置上填了什么数。在每个状态下,选择一个未填位置,检查那些填入仍能满足数独条件(合法)的数字。构成的新的局面即为该状态的“分支”。足够暴力的写法为依次对每个位置进......
  • 2023CSP-j复赛题解
    csp-j题解update:2024.6.18-2024.6.25:重构题解第一题:小苹果原题洛谷P9748思路n表示当前长度求几天取完:每天取走\((n-1)/3+1\)个苹果,记录几天取完第\(n\)个苹果第几天被取走:当\(n\bmod3=0\)时被取走时间复杂度约为\(O(\log_n)\)#include<iostream>......
  • [ARC105C] Camels and Bridge 题解
    [ARC105C]CamelsandBridge题解出自梦熊比赛后,梦熊比赛出原题了,忘周知。也许更好的阅读体验思路全排列,差分约束,二分。全排列\(n\leq8\),且要指定顺序,易想到用全排列枚举所有状态。差分约束在全排列之后,需要求得每种状态的最短距离。定义所有骆驼的编号的集合为\(S\)......
  • ABC 364 F - Range Connect MST 题解
    一副扑克牌,去掉1到K,剩下就是我,赛后十秒过,我是joker。......
  • CF613E Puzzle Lover 题解
    Description给定一个\(2\timesn\)的矩阵,每个位置上有一个小写字母。有一个长度为\(k\)的小写字符串\(w\),询问矩阵中有多少条有向路径满足以下条件:路径上的字母连起来恰好为\(w\)。不多次经过同一个位置。只能向上下左右四个方向走。\(n,k\le2\times10^3\),答案......
  • IOI2022 邮局 加强版 题解
    [IOI2000]邮局加强版题解考虑动态规划,设\(f_{i,j}\)为经过了\(i\)个村庄,正在建第\(j\)​个邮局的最优距离。以及\(w_{i,j}\)表示区间\([i,j]\)​内建一个邮局时的距离总和。\(a\)数组表示每个村庄的坐标编号。朴素版状态转移方程:\[f_{i,j}=\min(f_{i,j},f_{k,j......
  • 07-25 题解
    07-25题解原题出处(按顺序):CF1556ECF1234FP9746CF1316EP3651CF17CCF1842HA转化:括号序列如果\(a_i\>b_i\),则有\(a_i-b_i\)个左括号如果\(a_i\<b_i\),则有\(b_i-a_i\)个右括号(第一个+1的位置一定在第一个-1的位置的左侧,所以情况一用左括号......
  • 第二次测试部分题解 (c,d,g)
    c-一个欧拉函数模板题 1#include<iostream>2usingnamespacestd;34intmain()5{6intn;7cin>>n;8intr=n;9for(inti=2;i*i<=n;i++)10{11if(n%i==0)12{13r......
  • 第二次测试部分题解
    A——暴力枚举计数就好了,可以参考这段代码#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#definemod100003#defineMAN1000100charstr[10];intans;voidok(){ ans=0; intlen=0; for(inti=0;str[i]!='\0';i++) len++; if(l......
  • ABC260F 题解
    题面根据题目描述,原图为二分图,设两侧点集为\(S,T\),大小为\(s,t(s\le3\times10^5,t\le3\times10^3)\)。注意到有四元环当且仅当\(T\)中存在一个点对\((a,b)\)同时和\(S\)中的某两个点连边。可以先考虑暴力,一种想法是:考虑枚举\(S\)中的点\(c\),设和\(c\)连边的点......