首页 > 其他分享 >CF187E Heaven Tour

CF187E Heaven Tour

时间:2024-11-18 19:29:12浏览次数:1  
标签:q1 Heaven int isl Hth Tour ans push CF187E

题意

给定 \(n\) 个点,初始在 \(s\) 点,求走遍所有点的最小移动距离,以及方案,需要向左走恰好 \(l\) 次。

\(n \le 10 ^ 5\)。

Sol

难点在于想到枚举终点。

钦定当前若终点在起点右边,那么最优走法就是先向左走到底,然后向右走到底,然后最后再走到终点。

其中中间重复走的段,显然可以发现每一段至多被多走一次,用来多一个 \(l\) 少一个 \(r\),如果一段走了多次,还不如直接重复走旁边的两段。

对于两边本身就走两次的段,尽量全部走 \(l\),这样可以算出来中间需要多走多少次,注意到每次需要的次数是单调不降的,直接对顶堆维护即可。

求方案略显恶心,复杂度:\(O(n \log n)\)。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <queue>
#include <set>
#include <vector>
#define ll long long
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(ll x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

const int N = 1e5 + 5;

namespace Hth {

priority_queue <int> q1;
priority_queue <int, vector <int>, greater <int> > q2;

ll ans;

void insert(int x) { q2.push(x); }

int resize(int k) {
    while (q1.size() > k)
        ans -= q1.top(), q2.push(q1.top()), q1.pop();
    while (q1.size() < k && q2.size())
        ans += q2.top(), q1.push(q2.top()), q2.pop();
    return q1.size() == k;
}

void init() {
    while (q1.size()) q1.pop();
    while (q2.size()) q2.pop();
    ans = 0;
}

} //Hth

array <int, N> s;

vector <ll> solve(int n, int m, int k) {
    Hth::init();
    ll ans = 0, res = 2e18;
    for (int i = k + 1; i <= n; i++) {
        ll _res = 2e18;
        if (k - 1 + n - i >= m)
            _res = 2 * s[n] - s[i] + s[k];
        else if (Hth::resize(m - k - n + i + 1))
            _res = 2 * s[n] - s[i] + s[k] + 2ll * Hth::ans;
        /* if (i == 10) */
            /* cerr << m - k - n + i + 1 << " " << Hth::ans << " " << _res << "@@@@" << endl; */
        if (_res < res) res = _res, ans = i;
        if (i - 1 > k) Hth::insert(s[i] - s[i - 1]);
    }
    if (!ans) return vector <ll>(1, res);
    Hth::init();
    for (int i = k + 2; i < ans; i++)
        Hth::insert(s[i] - s[i - 1]);
    Hth::resize(m - k - n + ans + 1);
    /* cerr << m - k - n + ans + 1 << "@" << endl; */
    vector <ll> isl; multiset <int> req;
    isl.push_back(res);
    while (Hth::q1.size())
        req.insert(Hth::q1.top()), Hth::q1.pop();
    int tp0 = 0;
    for (int i = k - 1; i >= 2; i--)
        if (m > (k != 1) + (ans != n)) isl.push_back(i), m--, tp0++;
    if (k != 1) isl.push_back(1), m--;
    for (int i = 2; i <= k - tp0 - 1; i++)
        isl.push_back(i);
    set <int> tp;
    for (int i = k + 1; i < ans - 1; i++)
        if (i + 1 != ans && req.find(s[i + 1] - s[i]) != req.end() && m > (ans != n))
            tp.insert(i), req.erase(req.find(s[i + 1] - s[i])), m--;
    /* for (auto p : tp) */
        /* cerr << p << "@" << endl; */
    for (int i = k + 1; i <= ans - 1; i++) {
        /* if (i + 1 != ans && m > 1 && req.find(s[i + 1] - s[i]) != req.end()) */
            /* isl.push_back(i + 1), isl.push_back(i), m--, req.erase(req.find(s[i + 1] - s[i])), i += 2; */
        /* else */
            /* isl.push_back(i); */
        int lst = 0;
        while (tp.find(i + lst) != tp.end()) lst++;
        if (!lst) isl.push_back(i);
        else {
            for (int j = lst + i; j >= i; j--)
                isl.push_back(j);
            i += lst;
            /* isl.push_back(-1); */
        }
    }
    for (int i = ans + 1; i <= ans + (n - ans - 1) - (m - (ans != n)); i++)
        isl.push_back(i);
    if (ans != n) isl.push_back(n);
    for (int i = n - 1; i >= n - (m - (ans != n)); i--)
        isl.push_back(i);
    isl.push_back(ans);
    return isl;
}

bool _edmer;
int main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
    int n = read(), m = read(), k = read();
    for (int i = 1; i <= n; i++) s[i] = read();
    if (m == 0) {
        if (k != 1) return puts("-1"), 0;
        write(s[n] - s[1]), puts("");
        for (int i = 2; i <= n; i++)
            write(i), putchar(32);
        return puts(""), 0;
    }
    if (m == n - 1) {
        if (k != n) return puts("-1"), 0;
        write(s[n] - s[1]), puts("");
        for (int i = n - 1; i; i--)
            write(i), putchar(32);
        return puts(""), 0;
    }
    vector <ll> tp1 = solve(n, m, k);
    m = n - 1 - m, k = n - k + 1;
    for (int i = 1; i <= n; i++)
        s[i] = s[n] - s[i];
    reverse(s.begin() + 1, s.begin() + 1 + n);
    /* for (int i = 1; i <= n; i++) */
        /* cerr << s[i] << " "; */
    /* cerr << endl; */
    vector <ll> tp2 = solve(n, m, k);
    if (tp1.front() < tp2.front()) {
        write(tp1.front()), puts("");
        tp1.erase(tp1.begin());
        for (auto p : tp1)
            write(p), putchar(32);
        puts("");
    }
    else {
        write(tp2.front()), puts("");
        tp2.erase(tp2.begin());
        for (auto p : tp2)
            write(n - p + 1), putchar(32);
            /* cerr << p << " "; */
        puts("");
    }
    /* cerr << tp.front() << endl; */
    /* for (auto k : tp) */
        /* cerr << k << " "; */
    /* cerr << endl; */
    return 0;
}

标签:q1,Heaven,int,isl,Hth,Tour,ans,push,CF187E
From: https://www.cnblogs.com/cxqghzj/p/18553482

相关文章

  • P3577 [POI2014] TUR-Tourism
    P3577[POI2014]TUR-Tourism可能很多人看到这道题既可以从父亲更新到儿子,又可以从儿子更新到父亲的时候,很多人都跟我一样是这样的:于是这里分享一下我的一种思考。直径\(\le10\),可以先求出DFS生成森林,这样树高不超过\(10\)且没有横叉边,我们使返祖边是通过祖先限制后代,......
  • P9890 [ICPC2018 Qingdao R] Tournament 题解
    P9890[ICPC2018QingdaoR]Tournament题目传送门更好的阅读体验一道找规律的思维题。前置知识\(lowbit\)\(lowbit\)是指获取一个二进制数中最右边的\(1\)所对应的数值。具体地,\(lowbit\)可以通过对一个数取反然后加\(1\),再与原数进行按位与的方式来实现。intlow......
  • 358G AtCoder Tour
    358G思维题#include<bits/stdc++.h>#definelllonglongusingnamespacestd;intn,m,s,t,vis[55][55][2505],k;lldis[55][55][2505],v[55][55],ans;intmvx[]={-1,1,0,0};intmvy[]={0,0,-1,1};structNode{intx,y,d;};queue<Node>q;void......
  • tour cpp: std::variant 实现无继承层次的访问者模式
    std::variant是基于模板而实现的一种包括了一个标志位的高级union对象;可以完全替代如下场景:structst{inttype;unionun{inti;floatf;};};#include<iostream>#include<variant>template<class...base>structoverloaded:bas......
  • Playoff Tournament
    算法暴力思路显然观察到更改操作最多只影响一条链于是显然代码#include<bits/stdc++.h>constintMAXLEN=263000;intk;std::stringResult;intq;intMatch;charNew_Result;intpows[20]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,......
  • abc369E Sightseeing Tour
    有N个岛和M座双向桥,编号为i的桥连接岛U[i]和V[i],过桥耗时T[i],桥连接两不同的岛屿,两个岛之间可能会有多座桥。有Q组询问,每次询问给出K座桥,问从1号岛到N号岛的最少耗时,要求给出的K座桥分别至少经过1次。2<=N<=400;N-1<=M<=2E5;1<=U[i]<V[i]<=N;1<=T[i]<=1E9;1<=Q<=3000;1<=K[......
  • 【Tourism】Luoyang(1)
    文章目录洛阳1、龙门石窟(AAAAA)2、白马寺(AAAA)洛阳洛阳市,简称“洛”,古称成周、神都、洛邑、洛京,是河南省辖地级市、世界文化名城、首批国家历史文化名城、国家区域性中心城市、中原城市群副中心城市、“一带一路”重要节点城市,三线城市,国务院批复确定的河南省副中心城......
  • CF589H Tourist Guide
    昨晚码敲完了没保存,导致还原卡直接把我码肘没了。。。气死了只能重新敲了一遍。题面TouristGuide分析考虑每一个联通块分开处理。先将每一个联通块变为生成树,任意生成方式皆可。对于每一个联通块,一定可以构造一种组合方法,使得该联通块中最多只有一个关键点无法被选择。并......
  • SP1825 FTOUR2 - Free tour II 题解
    题目传送门前置知识点分治|树状数组解法维护点对信息,考虑点分治。本题比luoguP4149[IOI2011]Race多了个前缀查询\(\max\)。套个支持单点修改、区间查询\(\max\)的数据结构即可。直接线段树维护区间\(\max\)貌似会TLE,换成树状数组维护前缀\(\max\)即可。注......
  • [POI2014] TUR-Tourism
    [POI2014]TUR-Tourism题意给出一张图,在这张图中,任意两点间不存在节点数超过\(10\)的简单路径。第\(i\)个点被选的代价为\(C_i\),每个节点要么选,要么与它直接相连的点中至少有一个被选。求最小代价。思路图的生成树上状压动态规划。由于给出的是一张图,无法直接dp,我们可......