JZOJ 4611. 【NOI2016模拟7.11】接水问题 (贪心+A*+可持久化线段树)
Description:

https://gmoj.net/senior/#main/show/4611
题解:
先把A从大到小排序,最小的由排序不等式显然。
考虑类似第k短路的A*的做法。
定义状态为一个已经确定的前缀,它自己的代价显然,它的估价函数为把剩下的数字从小到大填的代价。
以自己代价+估价函数代价放入堆里一直扩展下一个即可,队列中会有\(n^2k\)个,加上求代价的复杂度,时间复杂度:\(O(n^3k)\)。
考虑优化扩展,注意假设要在下一位放数字,肯定是从小到大放,所以优化这个无用的扩展,可以减小一个n。
再考虑,一个状态一直放最小的到长度为n为止,这中间经过了很多状态,考虑把这些也优化了,
对状态重新定义为已知道了\(p[1..n]\)的值,前\(t-1\)个固定了,第\(t\)个可以变大,第\(t\)个现在是第\(w\)大,\(bz[t+1..n-1]\)表示\(p[x]\)能不能和\(p[x+1]\)交换。
发现状态只有\(O(k)\)个了,时间复杂度:\(O(nk)\)。
用可持久化线段树维护即可做到\(O(n~log~n+k~log~n)\)
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const ll inf = 1e18;
const int N = 2e5 + 5;
int n, k; ll a[N];
int cmpa(int x, int y) {
return x > y;
}
ll sum;
#define i0 t[i].l
#define i1 t[i].r
#define pii pair<ll, int>
#define fs first
#define se second
struct tree {
int l, r, p;
bool ban, lz;
pii x, y;
} t[N * 100]; int tt;
void upd(int i) {
t[i].x = min(t[i0].x, t[i1].x);
t[i].y = min(t[i0].y, t[i1].y);
}
void bt(int &i, int x, int y) {
i = ++ tt;
if(x == y) {
t[i].p = x;
t[i].x = t[i].y = pii(a[x] - a[x + 1], x);
return;
}
int m = x + y >> 1;
bt(i0, x, m); bt(i1, m + 1, y);
upd(i);
}
int pl, pr, px, py, pz;
void dgp(int &i, int x, int y) {
if(x == y) { px = t[i].p; return;}
int m = x + y >> 1;
if(pl <= m) dgp(i0, x, m); else dgp(i1, m + 1, y);
}
int fp(int &i, int x) {
pl = pr = x;
dgp(i, 1, n);
return px;
}
void kq(int &i) {
if(i) {
t[++ tt] = t[i]; i = tt;
t[i].ban = 0;
t[i].lz = 1;
t[i].x = t[i].y;
}
}
void down(int &i) {
if(t[i].lz) {
kq(i0), kq(i1);
t[i].lz = 0;
}
}
void dd(int &i, int x, int y) {
if(y < pl || x > pr) return;
t[++ tt] = t[i], i = tt;
if(x == y) {
t[i].y.fs += (ll) px * (a[x] - a[x + 1]);
if(t[i].ban) t[i].x = pii(inf, x); else
t[i].x = t[i].y;
if(py) t[i].p = pz;
return;
}
int m = x + y >> 1; down(i);
dd(i0, x, m); dd(i1, m + 1, y);
upd(i);
}
void xiu(int &i, int x, int y) {
int v = fp(i, x);
if(x > 1) {
py = 0;
pl = pr = x - 1, px = y - v;
dd(i, 1, n);
}
py = 1; pz = y;
pl = pr = x, px = v - y;
// pp("xiu %d %d %d %d\n", x, y, v, px);
dd(i, 1, n);
}
void du(int &i, int x, int y) {
if(y < pl || x > pr) return;
t[++ tt] = t[i], i = tt;
if(x == y) {
t[i].ban = 1;
t[i].x = pii(inf, x);
return;
}
int m = x + y >> 1; down(i);
du(i0, x, m); du(i1, m + 1, y);
upd(i);
}
void jz(int &i, int x) {
pl = pr = x;
du(i, 1, n);
}
void ddq(int &i, int x, int y) {
if(y < pl || x > pr) return;
if(x == y) {
px = t[i].ban; return;
}
int m = x + y >> 1; down(i);
ddq(i0, x, m); ddq(i1, m + 1, y);
}
int qry_ban(int &i, int x) {
pl = pr = x;
ddq(i, 1, n);
return px;
}
pii pu;
void ft(int &i, int x, int y) {
if(y < pl || x > pr) return;
if(x >= pl && y <= pr) {
pu = min(pu, t[i].x);
return;
}
int m = x + y >> 1; down(i);
ft(i0, x, m); ft(i1, m + 1, y);
}
pii qry(int &i, int t) {
pl = t + 1, pr = n - 1;
pu = pii(inf, 0);
ft(i, 1, n);
return pu;
}
int rt;
struct nod {
int g, t, w;
pii c;
ll s;
};
bool operator < (nod a, nod b) {
return a.s > b.s;
}
priority_queue<nod> q;
void build() {
bt(rt, 1, n);
nod b;
b.g = rt; b.t = 1; b.w = 2;
b.c = pii(a[1] - a[2], 1);
b.c = min(b.c, qry(b.g, b.t));
b.s = sum;
b.s += b.c.fs;
q.push(b);
}
void swap(nod &b, int x, int y) {
int v1 = fp(b.g, x), v2 = fp(b.g, y);
// pp(" swap %d %d %d %d\n", x, y, v1, v2);
// pp("%lld\n", qry(b.g, 1).fs);
xiu(b.g, x, v2); xiu(b.g, y, v1);
// pp("%lld\n", qry(b.g, 1).fs);
}
int mak(nod &b) {
if(b.w > n) {
b.t ++; b.w = b.t + 1;
if(b.t >= n) return 0;
}
b.c = pii(inf, 0);
if(!qry_ban(b.g, b.t)) {
b.c = pii((a[b.t] - a[b.w]) * (fp(b.g, b.w) - fp(b.g, b.t)), b.t);
}
b.c = min(b.c, qry(b.g, b.t));
if(b.c.fs == inf) return 0;
b.s += b.c.fs;
return 1;
}
void work(nod b) {
int x = b.c.se, y = x == b.t ? b.w : x + 1;
if(x == b.t) {
nod c = b;
swap(c, x, y);
c.w ++; kq(c.g);
if(mak(c)) q.push(c);
b.s -= b.c.fs;
jz(b.g, x);
if(mak(b)) q.push(b);
} else {
nod c = b;
swap(c, x, y);
c.t = x, c.w = x + 2;
kq(c.g);
if(mak(c)) q.push(c);
b.s -= b.c.fs;
jz(b.g, x);
if(mak(b)) q.push(b);
}
}
int main() {
freopen("water.in", "r", stdin);
freopen("water.out", "w", stdout);
scanf("%d %d", &n, &k);
fo(i, 1, n) scanf("%lld", &a[i]);
sort(a + 1, a + n + 1, cmpa);
fo(i, 1, n) sum += a[i] * i;
build();
pp("%lld\n", sum);
fo(ii, 1, k - 1) {
nod b = q.top(); q.pop();
pp("%lld\n", b.s);
work(b);
// pp("fs = %lld\n", qry(b.g, b.t).fs);
// pp("%d %d %lld %d\n", b.t, b.w, b.c.fs, b.c.se);
// fo(i, 1, n) {
// int x = b.c.se, y = x == b.t ? b.w : x + 1;
// int t = i == x ? y : (i == y ? x : i);
// pp("%d ", fp(b.g, t));
// }
// hh;
}
}
JZOJ 4611. 【NOI2016模拟7.11】接水问题 (贪心+A*+可持久化线段树)的更多相关文章
- [jzoj 6086] [GDOI2019模拟2019.3.26] 动态半平面交 解题报告 (set+线段树)
题目链接: https://jzoj.net/senior/#main/show/6086 题目: 题解: 一群数字的最小公倍数就是对它们质因数集合中的每个质因数的指数取$max$然后相乘 这样的子树 ...
- 【bzoj3524】【Poi2014】【Couriers】可持久化线段树(主席树)水题
[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62485671 向大(hei)佬(e)势力学(di ...
- 【模拟8.11】将军令(贪心&&树形DP)
只看45分的话,是树形DP....(当然也有能拿到70分+的大佬) 40分: 只考虑k==1的情况,树形DP 所以每个节点可能被父亲,自己,儿子控制 设f[MAXN][3],0表示儿子,1表示自己,2 ...
- 2019.02.11 bzoj1568: [JSOI2008]Blue Mary开公司(线段树)
传送门 题意简述:维护整体加一条线段,求单点极值. 思路: 直接上李超线段树维护即可. 代码: #include<bits/stdc++.h> #define ri register in ...
- 2018.11.06 bzoj1835: [ZJOI2010]base 基站选址(线段树优化dp)
传送门 二分出每个点不需要付www贡献的范围,然后可以推出转移式子: f[i][j]=f[i−1][k]+value(k+1,j)+c[i]f[i][j]=f[i-1][k]+value(k+1,j) ...
- 2018.06.27 NOIP模拟 节目(支配树+可持久化线段树)
题目背景 SOURCE:NOIP2015-GDZSJNZX(难) 题目描述 学校一年一度的学生艺术节开始啦!在这次的艺术节上总共有 N 个节目,并且总共也有 N 个舞台供大家表演.其中第 i 个节目的 ...
- hdu 5475 模拟计算器乘除 (2015上海网赛H题 线段树)
给出有多少次操作 和MOD 初始值为1 操作1 y 表示乘上y操作2 y 表示除以第 y次操作乘的那个数 线段树的叶子结点i 表示 第i次操作乘的数 将1替换成y遇到操作2 就把第i个结点的值 替换成 ...
- [JZOJ6075]【GDOI2019模拟2019.3.20】桥【DP】【线段树】
Description N,M<=100000,S,T<=1e9 Solution 首先可以感受一下,我们把街道看成一行,那么只有给出的2n个点的纵坐标是有用的,于是我们可以将坐标离散化至 ...
- jzoj5986. 【WC2019模拟2019.1.4】立体几何题 (权值线段树)
传送门 题面 题解 不难看出每个点的大小为行列限制中较小的那一个(因为数据保证有解) 对于行的每个限制,能取到的个数是列里限制大于等于它的数的个数,同理,对于列是行里大于它的个数(这里没有等于,为了避 ...
随机推荐
- 洛谷 P 4180 次小生成树
题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...
- LeetCode 56,57,60,连刷三题不费劲
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第34篇文章,刚好接下来的题目比较简单,很多和之前的做法类似.所以我们今天出一个合集,一口气做完接下来的57.5 ...
- 集训模拟赛-1-T2
好了不要在铺垫了直接整吧就 题目拿来!!!!!!! 倒水 (water) (256MB,1s) [问题描述] 你有一个水桶(记为 0),两个杯子(记为 1,2).水桶中的水量无限,容量也无限.1 号杯 ...
- xenomai内核解析之xenomai的组成结构
@ 目录 一.xenomai 3 二.xenomai3 结构 这是第二篇笔记. 一.xenomai 3 从xenomai3开始支持两种方式构建linux实时系统,分别是cobalt 和 mercury ...
- libevent(一)定时器Demo
开始研究libevent,使用的版本是2.0.22. 实现一个定时器:每2秒执行一次printf. #include <stdio.h> #include <stdlib.h> ...
- CentOS安装boost
安装其实很简单的: tar zxvf boost_1_59_0.tar.gz cd boost_1_59_0 ./bootstrap.sh --prefix=/usr/local/boost ./b2 ...
- RabbitMQ的使用(二)- RabbitMQ服务在单机中做集群
RabbitMQ的使用(二)- RabbitMQ服务在单机中做集群 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/128371 ...
- C# 获取从1月至12月的月初时间和月末时间
public IActionResult GetMonthData() { var dataList = new List<object>(); var currentMonth = Da ...
- python --文件读取数据
读取整个文件: 首先创建一个文件,例如我创建了一个t x t文件了. 然后我想读取这个文件了,我首先将上面的这个文件保存在我即将要创建的Python的文件目录下, 即读取文件成功. 解析: 函数ope ...
- JQ选择器-选择符合条件的元素,获取对应关系元素
如果你想寻找id以“sub_”开头的元素,你可以使用: $("*[id^='sub_']") 如果你想寻找id以“trim”结尾的元素,你可以使用: $("*[id$=' ...