珍珠

题意

一共n课珍珠,m颗悬挂,其余在桌子上。如图所示。

仆人每天从某一端“借”一颗珍珠珠。主人每天都会检查悬挂的珍珠数目。

每颗珍珠的摩擦系数都是kkk.

若有wh>kwtw_h \gt kw_twh​>kwt​,则珍珠落地,被主人发现。

珍珠iii的质量是wiw_iwi​,价格是cic_ici​.

问仆人最大可以借多少价钱的珍珠,并输出借的珍珠数目和一种“借”的方案。

分析

增加限定条件

如果我们增加题目的限定条件,不允许从悬挂端取珍珠。显然,从左边能取的最大珍珠数有一个限度。并且符合单调性。即,如果可以取aaa颗,则一定可以取b(b&lt;a)b(b&lt;a)b(b<a)颗;如果取aaa颗不行,则取b(b&gt;a)b(b&gt;a)b(b>a)一定不行。故可以二分

当然,如果只是如此的话,直接枚举比二分划算,因为每次求wtw_twt​的代价是线性的,除非预先线性求出前缀和,之后可以Θ(1)\Theta(1)Θ(1).

去掉限定条件

现在假设我们通过一系列合法的操作已经去掉了若干颗悬挂端末尾的珍珠,达到了末尾珠子是endendend号的状态。然后加上上面所述的限定条件,则在这种状态下的最优情况由以上可知可以二分求得。

如此来看,我们还需要解决的问题有:

  1. 状态仅由结尾珠子是endendend表示知否足够?即如此做是否考虑了所有情况?
  2. 如何确定状态是否可由合法操作得到。

对于1,事实是足够的。endendend确定了,悬挂的珠子就确定了,即whw_hwh​确定了,那么能躺在桌子上的最后的极限情况就是不变的。因为每颗珠子质量非负,因此在这个状态是可达的情况下,在达到这个状态之前去除左边的还是达到之后去除从效果上来看没有差异。因此结尾为endendend,开头只需要设置为1号即考虑了所有情况。

对于2,因为珠子质量非负,可以肯定的是左边桌子端一颗不能少。因为不可能这么存在一种情况。

两种情况S1,S2S_1,S_2S1​,S2​的珠子,除了S1S_1S1​比S2S_2S2​左边少了几颗,剩余的从右边看都是一样的。而S1S_1S1​经过一番合法操作可以到达末尾为endendend号珠子的状态,而S2S_2S2​却无法到达。事实上,如果S1S_1S1​可以,只要S2S_2S2​抄S1S_1S1​的操作就一定可以。

知道了以上这点,显然我们的操作就无需选择了,只剩下不断的取下珠子,直到结尾是endendend即可。然后需要保证每一步取完都是不会落地的。因此,从后往前枚举end,尝试取就好。

Code

#include <bits/stdc++.h>
using namespace std; class Sum
{
private:
vector<int> sum; public:
Sum()
{
} void set(vector<int> &val)
{
sum.clear();
if (val.empty())
return;
sum.push_back(val[0]);
int sz = val.size();
for (int i = 1; i < sz; ++i)
sum.push_back(sum[i - 1] + val[i]);
} inline int get_sum(int i)
{
return i >= 0 ? sum[min<int>(i, sum.size())] : 0;
} // sum[l..r]
inline int get_sum(int l, int r)
{
return get_sum(r) - get_sum(l - 1);
} void print()
{
for (auto x : sum)
cout << x << " ";
cout << endl;
}
}; class Pearls
{
private:
int total_cnt;
int hang_cnt;
int k;
vector<int> weight;
vector<int> cost;
Sum w;
Sum c;
struct Ans
{
int l;
int r;
int cost;
bool valid;
void update(int l0, int r0, int cost0)
{
if (valid)
{
if (cost0 > cost)
{
l = l0;
r = r0;
cost = cost0;
}
}
else
{
l = l0;
r = r0;
cost = cost0;
valid = true;
}
}
void print()
{
cout << l + r << " " << cost << endl;
string s(r,'H');
string ss(l,'T');
cout<<s<<ss<<endl;
}
}ans; public:
void init()
{
cin >> total_cnt >> hang_cnt >> k;
weight.resize(total_cnt + 1);
cost.resize(total_cnt + 1);
weight[0] = cost[0] = 0;
for (int i = 1; i <= total_cnt; ++i)
{
cin >> weight[i] >> cost[i];
}
w.set(weight);
c.set(cost);
}
void work()
{
int w_h;
int w_t;
int table_end;
for (int end = total_cnt; end >= hang_cnt; --end)
{
table_end = end - hang_cnt;
w_h = w.get_sum(table_end + 1, end);
w_t = w.get_sum(1, table_end);
if (w_h > k * w_t)
{
// 前面一颗珠子不少仍旧无法实现这个状态的平衡,则无法实现。
// 因为end更小的无法绕过这一end的状况。所以更小的end也无需考虑。
break;
}
int l = 1; // is ok 可以维持平衡
int r = table_end + 1; // is not ok 不可以维持平衡
while (r - l > 1)
{
int m = l + (r - l) / 2;
w_t = w.get_sum(m, table_end);
if (w_h <= k * w_t)
{ // m is ok
l = m;
}
else
{
r = m;
}
}
ans.update(l-1, total_cnt - end, c.get_sum(1, l - 1) + c.get_sum(end + 1, total_cnt));
}
ans.print();
}
}; int main()
{
Pearls *p = new Pearls();
p->init();
p->work();
delete p;
return 0;
}

codeforces 99999/553 Sultan's Pearls Solution 珍珠 题解的更多相关文章

  1. Codeforces Round #609 (Div. 2)前五题题解

    Codeforces Round #609 (Div. 2)前五题题解 补题补题…… C题写挂了好几个次,最后一题看了好久题解才懂……我太迟钝了…… 然后因为longlong调了半个小时…… A.Eq ...

  2. Codeforces Round #553 (Div. 2) C

    C. Problem for Nazar time limit per test 1 second memory limit per test 256 megabytes input standard ...

  3. Codeforces Round #553 (Div. 2) D题

    题目网址:http://codeforces.com/contest/1151/problem/D 题目大意:给出n组数对,(ai , bi),调整这n组数对的位置,最小化 ∑(ai*( i -1)+ ...

  4. Codeforces Round #553 (Div. 2) C题

    题目网址:http://codeforces.com/contest/1151/problem/C 题目大意:给定奇数集和偶数集,现构造一个数组,先取奇数集中一个元素1,再取偶数集二个元素2,4,再取 ...

  5. Codeforces Round #553 (Div. 2) B题

    题目网址:http://codeforces.com/contest/1151/problem/B 题目大意:给定一个n*m的矩阵,问是否可以从每一行中选择一个数,使得这n个数异或大于0,如果可以还要 ...

  6. Codeforces Round #553 (Div. 2) A题

    题目网址:http://codeforces.com/contest/1151/problem/A 题目大意:给定一个由大写字母构成的字符串和它的长度,有这样的操作,使任意一个字母变成与其相邻的字母, ...

  7. Codeforces Round #553 (Div. 2) E 贡献

    https://codeforces.com/contest/1151/problem/E 题意 一条长n的链,每个点上有值\(a[i]\),定义\(f(l,r)\)为该区间的\(值\)所代表的点留下 ...

  8. Codeforces Round #553 (Div. 2) C 等差数列求和 + 前缀和

    https://codeforces.com/contest/1151/problem/C 题意 有两个等差数列(1,3,5,..),(2,4,6,...),两个数列轮流取1,2,4,...,\(2^ ...

  9. Codeforces Round #551 (Div. 2) EF Solution

    E. Serval and Snake 对于一个矩形,如果蛇的一条边与它相交,就意味着这条蛇从矩形内穿到矩形外,或者从矩形外穿到矩形内.所以如果某个矩形的答案为偶数,意味着蛇的头尾在矩形的同一侧(内或 ...

随机推荐

  1. 分区格式化大于2 TiB磁盘

    如果您要分区格式化一块大于2 TiB的作数据盘用的云盘(本文统一称为 大容量数据盘,小于2 TiB的数据盘统称为 小容量数据盘),您必须采用GPT分区形式.本文档描述了如何在不同的操作系统里分区格式化 ...

  2. Day2前端学习之路——HTML基本知识

    课程目标: 通过制作自己的简历,更加清楚地了解HTML是什么,HTML5是什么.学习基本的HTML标签,理解HTML语义化概念 任务一:回答问题 1.HTML是什么,HTML5是什么? HTML是一种 ...

  3. Day1前端学习之路——概述

    终于下定决心要好好学习前端知识了,以后会把学习过程中的一些随笔记录在这里.HTML.CSS.JavaScript这三大前端语言在大三的时候就有所接触,但是学习的不够深入,这一次希望能够坚持下去. 学习 ...

  4. 【全集】大数据Linux基础

    课程介绍 本课程是由猎豹移动大数据架构师,根据公司大数据平台的运维情况,精心设计和打磨的大数据必备Linux课程.通过本课程的学习大数据新手能够少走弯路,快速掌握Linux常用命令及Shell编程,为 ...

  5. Java中的合并与重组(上)

    通过优锐课核心java学习笔记中,我们可以看到,码了很多专业的相关知识, 分享给大家参考学习. 虽然在Git中合并和重组是相似的,但它们具有两种不同的功能. 要保持自己的历史记录整洁或完整,这是你应该 ...

  6. Cesium动态绘制实体(点、标注、面、线、圆、矩形)

    //自定义绘制图形,支持 点,线,面,矩形,圆,标识,可自定义绘制过程中的和绘制完的预览 this.drawGraphic = function(view,_mode,_callback,_Graph ...

  7. mysql 查询语句的执行顺序(重重点)

    一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...

  8. Dalvik虚拟机和Art虚拟机

    Dalvik虚拟机 DVM是Dalvik Virtual Machine的缩写,是Android4.4及以前使用的虚拟机,所有android程序都运行在android系统进程里,每个进程对应着一个Da ...

  9. 【DTOJ】1001:长方形周长和面积

    DTOJ 1001:长方形周长和面积  解题报告 2017.11.05 第一版  ——由翱翔的逗比w原创 题目信息: 题目描述 已知长方形的长和宽,求长方形的周长和面积? 输入 一行:空格隔开的两个整 ...

  10. mac本地安装全局包报错npm WARN checkPermissions

    安装本地全局包时,本地报错 npm WARN checkPermissions Missing write access to /Users/xxx/.nvm/versions/node/v11.10 ...