驯龙高手 题解
驯龙高手 题解
原题题目不是这个但是我实在看不懂他起的这个题目是什么含义所以就重新起了。题目里的主角的名字我也换成了一个朋友的设定名字。
题目描述:
咪唑有
但是龙很好斗,如果咪唑交上的朋友中,有两条龙力量值不相等,那么他们会打架。咪唑不想他的朋友打架。咪唑化学灰常厉害,所以他可以配药剂来改变龙龙们的力量值。咪唑有两种用同一原料配成的药剂,分别是:
- 强化药剂:使某条龙的力量值增加
点,耗费 份原料; - 弱化药剂:使某条龙的力量值减少
点,耗费 份原料。
在第
输入格式
第一行三个数
第二行
样例输入
5 3 2 5 1 4 2 3
样例输出
0 8 11 13 15
思路:
首先这个题感觉就是另一道题的加强版。我之前也写过题解。建议先看那道题再回来看这篇题解。
那道题可以看作这道题
那么
维护一个有序的序列,同时还要支持按排名查询,维护区间和,平衡树!
FHQ 轻松水过。复杂度
代码:
#include<bits/stdc++.h> using namespace std; const int N = 1e5+10; const long long INF = 0x3f3f3f3f3f3f3f3f; inline int read(){ int x = 0; char ch = getchar(); while(ch<'0' || ch>'9') ch = getchar(); while(ch>='0'&&ch<='9') x = x*10+ch-48, ch = getchar(); return x; } int n, A, B; #define ll long long struct node{ int val, rnd, siz; ll sum; int ls, rs; }; int root; struct FHQ_Treap{ node tree[N]; #define ls(x) tree[x].ls #define rs(x) tree[x].rs int idx; int New(int val){ tree[++idx] = (node){val, rand(), 1, val, 0, 0}; return idx; } void push_up(int x){ tree[x].siz = tree[ls(x)].siz+tree[rs(x)].siz+1; tree[x].sum = tree[ls(x)].sum+tree[rs(x)].sum+tree[x].val; } void split(int pos, int &l, int &r, int K){ if(!pos) return l = r = 0, void(); int tmp = tree[ls(pos)].siz+1; if(K >= tmp){ l = pos; split(tree[pos].rs, tree[pos].rs, r, K-tmp); push_up(l); } else{ r = pos; split(tree[pos].ls, l, tree[pos].ls, K); push_up(r); } } void split_by_val(int pos, int &l, int &r, int K){ if(!pos) return l = r = 0, void(); if(K >= tree[pos].val){ l = pos; split_by_val(tree[pos].rs, tree[pos].rs, r, K); push_up(l); } else{ r = pos; split_by_val(tree[pos].ls, l, tree[pos].ls, K); push_up(r); } } int merge(int l, int r){ if((!l) || (!r)) return l | r; if(tree[l].rnd < tree[r].rnd){ tree[l].rs = merge(tree[l].rs, r); push_up(l); return l; } else{ tree[r].ls = merge(l, tree[r].ls); push_up(r); return r; } } void insert(int val){ int dl, dr; split_by_val(root, dl, dr, val); root = merge(merge(dl, New(val)), dr); } int findr(int pos){ while(rs(pos)){ pos = rs(pos); } return pos; } int findl(int pos){ while(ls(pos)){ pos = ls(pos); } return pos; } }fhq; int geta(int len){ int ret = (1ll*len*B/(A+B)); return ret; } int getb(int len){ int ret = (int)ceil(1.0*(double)len*B/(A+B)); return ret; } ll calc(int pos, int len){ int dl, dr; fhq.split(root, dl, dr, pos); ll vl = fhq.findr(dl); ll vr = fhq.findl(dr); ll reta = INF, retb = INF; if(vl){ vl = fhq.tree[vl].val; reta = 0; if(dl) reta += (vl * pos - fhq.tree[dl].sum)*A; if(dr) reta += (fhq.tree[dr].sum - vl * (len - pos))*B; } if(vr){ vr = fhq.tree[vr].val; retb = 0; if(dl) retb += (vr * pos - fhq.tree[dl].sum)*A; if(dr) retb += (fhq.tree[dr].sum - vr * (len - pos))*B; } root = fhq.merge(dl, dr); return min(reta, retb); } int main(){ srand(time(0)); n = read(), A = read(), B = read(); for(int i = 1, tmp; i<=n; ++i){ tmp = read(); fhq.insert(tmp); int mda = geta(i); int mdb = getb(i); ll ans = 0x3f3f3f3f3f3f3f3f; if(mda > 0 && mda <=i) { ans = min(ans, calc(mda, i)); } if(mdb > 0 && mdb <=i){ ans = min(ans, calc(mdb, i)); } printf("%lld\n", ans); }//A = B, FHQ, 每次按排名查中位数。 // 将序列分为 a:b 的两段即可www(保险起见 return 0; }
后记:
赛时 1.5h 搞完的(大概 20min 花在了造数据测试上)……还是太菜了。赛后有很多做法,比如
反正只有我最菜就对了 xwx。