@xiaoziyao
2021-05-05T08:23:58.000000Z
字数 1387
阅读 1139
解题报告
CF1515I Phoenix and Diamonds解题报告:
似乎是你谷首杀,针不戳。
种钻石,一颗第种钻石重量为,价值为,一开始第中钻石的库存为。接下来进行次操作:
神奇的题目,感觉没有CF*3400评分这么夸张,不过这数据确实强。
由于钻石种类已经给定,因此我们可以知道拿钻石的优先级。
发现处理询问的复杂度与总得有点关系,看的数据范围就大胆猜想复杂度要带,那么考虑如何每次至少把除二。
设的最高位为,对于第位,设一个钻石是“轻的”当且仅当其重量小于,否则如果它的重量小于,那么它是“重的”,一个很显然的结论就是在最高位不变的情况下不能取多于一个“重的”钻石。
自然而然地设表示对于第位,到“轻的”钻石价值和与重量和,表示对于第位,到“轻的”钻石重量加上一个最小的“重的”钻石的重量之和。
状态是的,不好存储,考虑上线段树,将上面的区间改为其对应线段树上的结点,那么很容易写出一个的来动态维护这三个数组。
查询部分,我们就先判掉叶子结点的情况,然后考虑重钻石与轻钻石都可以取走的情况,然后再判一判是不是只能取轻钻石,如果都不是的话就递归两个儿子处理。
记得动态维护当前的最高位。
时间复杂度:。(复杂度不太会证/kel)
long long query(int l,int r,int now){//calc()是维护c的最高位ω的函数
if(l==r){
long long num=min(a[id[l]],c/w[id[l]]);
c-=num*w[id[l]],calc();
return num*v[id[l]];
}
if(lightw[now][omega]<=c){
long long res=lightv[now][omega];
c-=lightw[now][omega],calc();
return res;
}
if(lightw[now][omega-1]<=c&&c<extra[now][omega-1]){
long long res=lightv[now][omega-1];
c-=lightw[now][omega-1],calc();
return res;
}
int mid=(l+r)>>1;
return query(l,mid,lc[now])+query(mid+1,r,rc[now]);
}