首页 > 其他分享 >Atcoder ABC364 D-F

Atcoder ABC364 D-F

时间:2024-07-30 11:28:42浏览次数:11  
标签:q1 Atcoder 菜肴 int dots find dp ABC364

Atcoder ABC364 D-F

D - K-th Nearest

链接:

D - K-th Nearest (atcoder.jp)

简要题意:

问题陈述

在一条数线上有 \(N+Q\) 个点 \(A_1,\dots,A_N,B_1,\dots,B_Q\) ,其中点 \(A_i\) 的坐标为 \(a_i\) ,点 \(B_j\) 的坐标为 \(b_j\) 。

请就每个点 \(j=1,2,\dots,Q\) 回答下面的问题:

  • 设 \(X\) 是 \(A_1,A_2,\dots,A_N\) 中最靠近点 \(B_j\) 的 \(k_j\) 点。求点 \(X\) 与 \(B_j\) 之间的距离。更正式地说,设 \(d_i\) 是点 \(A_i\) 与 \(B_j\) 之间的距离。将 \((d_1,d_2,\dots,d_N)\) 按升序排序,得到序列 \((d_1',d_2',\dots,d_N')\) 。求 \(d_{k_j}'\) .

思路:

  • 找一个第k大的a中某个点与b的距离 d, 我们会发现一个性质:
  • d越大,我们就会包含更多a中的数字 满足单调性
  • 我们保证包含的数字>=k
  • 然后最小化d
  • 这即是二分

代码:

const int N = 200005;
int a[N];
void solve(){
    int n,q;
    cin >> n >> q;
    for(int i = 1; i <= n;i++){
        cin >> a[i];
    }
    sort(a+1,a+1+n);
    while(q--){
        int d,k;
        cin >> d>>k;
        int l = 0,r = 1e12,ans= 0;
        while(l<=r){
            int mid = (l + r) >> 1;
            int ls = d - mid,rs = d + mid;
            int qs = upper_bound(a+1,a+1+n,rs) - lower_bound(a+1,a+1+n,ls);
            if(qs >= k){
                r = mid - 1;
                ans = mid;
            }else{
                l = mid + 1;
            }
        }
        cout << ans << endl;
    }
}

E - Maximum Glutton

链接:

E - Maximum Glutton (atcoder.jp)

简要题意:

\(N\) 道菜。这些菜肴的编号从 \(1\) 到 \(N\) ,菜肴 \(i\) 的甜度为 $$A_i$$ ,咸度为 \(B_i\) 。

你可以选择吃任意菜肴,吃过的菜肴的总甜度超过 \(X\) 或总咸度超过 \(Y\) ,他就不会再吃任何菜肴。

最多吃多少道菜?

思路:

  • 很明显想到dp
  • 怎么dp? 设$$dp[i][j][k]$$为前i个菜肴不超过x并且不超过y的能获得的最大奖牌数?? ,根据数据量,这样定义显然不行
  • 我们可以把奖牌数开一个维度,然后x开一个维度,记录消耗的y
  • 转移方程即: $$dp[i][j][k] = min(dp[i][j][k],dp[i - 1][j - 1][k - a[i]] +b[i])$$
  • 表示前i个数获得j个菜肴并且用了k个甜值所消耗的最小咸值
  • 明显是个背包,所以倒序枚举,优化一维;

代码:

const int N = 200005;
int a[N],b[N];
void solve(){
    int n,x,y;
    cin >> n >> x >>y;
    for(int i = 1;i<=n;i++){
        cin >> a[i] >>b[i];
    }

    int dp[n + 1][x + 2];
    for(int i = 0;i<=n;i++){
        for(int j = 0;j<=x;j++){
            dp[i][j] = inf;
        }
    }
    dp[0][0] = 0;
    for(int i = 1;i<=n;i++){
        for(int c = i;c>=1;c--){
            for(int k = x;k>=a[i];k--){
                dp[c][k] = min(dp[c][k],dp[c-1][k-a[i]]+b[i]);
            }
        }
    }
    int ans = 0;
    for(int i = 0;i<=n;i++){
        for(int j = 0;j<=x;j++){
            if(dp[i][j] <= y){
               ans = max(ans,i);
            }
        }
    }
    cout << min(ans+1,n) <<endl;

}

F - Range Connect MST

链接:

[F - Range Connect MST (atcoder.jp)](https://atcoder.jp/contests/abc364/tasks/abc364_e)

简要题意:

有一个图,其顶点有 \(N + Q\)个 ,编号为 \(1, 2, \ldots, N + Q\) 。最初,该图没有边。

对于这个图,请依次对 \(i = 1, 2, \ldots, Q\) 执行以下操作:

  • 对于每个满足 \(L_i \leq j \leq R_i\) 的整数 \(j\) ,在顶点 \(N + i\) 和 \(j\) 之间添加一条代价为 \(C_i\),的无向边。

完成所有操作后,确定图形是否相连。如果相连,求该图的最小生成树的代价。

思路:

  • 首先数据量大,不能真正建边
  • 集合分为两部分,第一部分是 $ 1, 2, \ldots, N$ 第二部分是 \(N+1,N+2, \ldots, N+Q\)
  • 第二部分要想和第一部分连边 必定会用一次C的价值去连边 所以答案必定 有 \(\sum c\)
  • 然后怎么让第一部分内部自己去连边呢,得靠第二部分去中转,我们可能会有多个l,r覆盖同一个区间,那么我们取最小值去连 l,l+1 等边,即是最小的生成树
  • 此部分可用并查集实现
  • 因为每个区间建完边后不会再访问
  • 时间复杂度\(O(NlogN + QlogQ)\)

代码:

const int N = 2e5+5;
struct quarys{
    int l,r,c;
    bool operator<(const quarys &q)const{
        return c < q.c;
    }
}q1[N];
struct DSU {
    vector<int> f, siz;
    DSU() {}
    DSU(int n) {
        init(n);
    }
    void init(int n) {
        f.resize(n);
        iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    
    int find(int x) {
        while (x != f[x]) {
            x = f[x] = f[f[x]];
        }
        return x;
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) {
            return false;
        }
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};
int n,q;
void solve(){
    cin >> n  >> q;
    ll ans = 0;
    DSU dsu(n + 1);
    for(int i = 0 ;i < q;i++){
        int l,r,c;
        cin >> l >> r >> c;
        q1[i].l=l;
        q1[i].r=r;
        q1[i].c=c;

    }
    sort(q1,q1+q);
    for(int i = 0;i < q;i++){
        int l = q1[i].l,r=q1[i].r,c=q1[i].c;
        ans+=c;
        for(int x = dsu.find(l);x<r;x=dsu.find(x)){
            ans+=c;
            dsu.merge(x + 1,x);

        }
    }
    if(dsu.find(1) != n){
        cout << -1;
        return;
    }
    cout << ans <<endl;
}

标签:q1,Atcoder,菜肴,int,dots,find,dp,ABC364
From: https://www.cnblogs.com/bananawolf/p/18332018

相关文章

  • Solution - Atcoder YPC2019E Odd Subrectangles
    首先对于\(0/1\)和为奇数,转化为异或为\(1\)来考虑。考虑如果已经确定了行的选取,又该如何计数。考虑对于每一列,都处理好在对应行的位置的异或值。然后记\(\operatorname{c}_0,\operatorname{c}_1\)表示列异或值为\(0/1\)的数量。知道了\(\operatorname{c}_0,\op......
  • Solution - Atcoder UTPC2023P Priority Queue 3
    考虑找一些关于合法的\(X\)加入的数的判定条件。假设遇到了一个\(\operatorname{pop}\)操作,令这里删除的数为\(a_i\),显然\(X\)中的数应该要有\(a_i\),其次\(X\)中其他的加入的数要么\(>a_i\)要么是\(a\)中的元素(在前面的\(\operatorname{pop}\)就已经被删了)。于......
  • ABC364F
    区间连边先想到线段树优化建图,但显然的是这样建图求MST根本没法做。需要另想他法。前两天刚做了弹跳,此题并没有直接建图,而是模拟了Dijkstra来跑最短路。同理,此题我们也可以不直接建图,而是通过模拟Kruskal来求MST。将边按照权值从小到大排序,注意到连完边后\([l,r]\)的每......
  • AtCoder Beginner Contest 362
    AtCoderBeginnerContest362前言vp的时候出了四题,被C题卡了一会,很久才出,D题是dijkstra的板子,改下条件即可,E题是个计数dp,这类题一直不怎么擅长,想起之前杭电第一场那个序列立方的题也是类似这种计数dp,需要加强练习。A-BuyaPen(atcoder.jp)思路判断两两最小。......
  • Solution - Atcoder ABC280Ex Substring Sort
    对于这种子串问题,且有多个基础串,一个比较直观的想法就是先上个广义SAM。考虑SAM与字典序如何联系上。因为跳\(\operatorname{fail}\)相当于是删除子串的一个前缀,直接这样子明显是不行的,因为跳了\(\operatorname{fail}\)字典序没有一个很直观地表示。但是反过来考虑反串,......
  • ABC364 DEF 题解
    ABC364DEF题解D-K-thNearest题目链接赛时想了一个(也许确实是对的)做法,但是代码太难写,一直没写出来……看了官方题解才发现正解其实也很简单……本题最关键的一点是要转换思路:与其考虑“离某个点第\(k\)近的点在哪”,不如考虑“离某个点距离不超过\(x\)的点有多少个”。......
  • Solution - Atcoder ARC114F Permutation Division
    令\(a\)为题目中的\(P\)。首先考虑后手的重排策略是什么。因为\(a\)是个排列,元素互不相同,那么肯定就是按照每一段的第一个数的大小,越大的放在越前面。那么当\(a_1\lek\)的时候,显然先手会把以\(1\simk\)开头来划分段。因为否则存在一个开头\(>k\)的段,后手把其放......
  • [题解]ABC364 A~F
    A-GluttonTakahashi给定\(n\)道菜,每道菜要么是甜的(用sweet表示),要么是咸的(用salty表示)。必须按顺序吃,如果连续吃到\(2\)个甜的菜,就会浑身难受吃不下去了。请问是否能吃完这些菜。按题意模拟即可,只要前\(n-1\)个元素中有连续的sweet就输出No。点击查看代码#include<bits/s......
  • AtCoder Beginner Contest 363 题解 A-D(待补充)
    A-PilingUp1.1思路其实就是向上取百位的整,需要增加多少,123则为200-123=177;1.2代码voidsolve(){intn;cin>>n;intt=n/100;cout<<(t+1)*100-n;}B-JapaneseCursedDoll 2.1思路就是判断最少需要多少天,会有大于等于P个人......
  • AtCoder Beginner Contest 363
    比赛地址添加链接描述A-PilingUp算法:模拟题目大意在AtCoder竞赛平台中,用户的等级通过正整数分数表示,并根据分数显示相应数量的^符号。分数与^符号显示的规则如下:当分数在1到99(包括99)之间时,显示一个^。当分数在100到199(包括199)之间时,显示两个^。......