珍珠

题意

一共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. js类的constructor中不支持异步函数吗?

    解决方案: 1.如果是普通函数,可以用async 和await来解决你的问题但你这个是在constructor里,constructor 的作用是返回一个对像实例,如果加了async就变成返回一个pr ...

  2. Laravel + Serverless Framework 快速创建 CMS 内容管理系统

    今天,为大家带来一篇 Laravel + Serverless Framework 的综合实战,里面信息量有点多,大家仔细看哦- 首先,我来介绍下主要的本地环境吧: Git:不多说,只要会敲代码就应该 ...

  3. C语言switch中case后跟随break语句

    1.case后面的常量表达式实际上只起语句标号作用,而不起条件判断作用,即“只是开始执行处的入口标号”.因此,一旦与switch后面圆括号中表达式的值匹配,就从此标号处开始执行:而且执行完一个case ...

  4. linux 基础入门(9) 系统服务 systemctl 与 xinted的运用

    9.系统服务 9.1系统服务 可以把计算机理解为一个地点比如中关村大街系统服务理解为中关村大街的理发店.饭店.商场等等,每一个都是一个系统服务,为客户提供不同内容的服务 服务:常驻在内存中的程序,且可 ...

  5. Spring Boot JPA分页 PageRequest报错

    在使用Spring Boot JPA分页 PageRequest分页时,出现如下错误: 本来以为是包导入出现了问题,结果发现并不是.导入包如下: 后来在网上查找相关资料,发现这样的用法,好像也可以用, ...

  6. Centos7 防火墙开放端口,查看状态,查看开放端口

    CentOS7 端口的开放关闭查看都是用防火墙来控制的,具体命令如下: 查看防火墙状态:(active (running) 即是开启状态) [root@WSS bin]# systemctl fire ...

  7. CF1311E Construct the Binary Tree

    膜这场比赛的 \(rk1\) \(\color{black}A\color{red}{lex\_Wei}\) 这题应该是这场比赛最难的题了 容易发现,二叉树的下一层不会超过这一层的 \(2\) 倍,所 ...

  8. Java学习之String、StringBuffer、StringBuilder

    String 我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多.JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池 ...

  9. es的分布式架构原理是什么?

    es的分布式架构原理是什么? 1.首先说一些分片(shard)是什么? ES中所有数据均衡的存储在集群中各个节点的分片中,会影响ES的性能.安全和稳定性 每个shard都是一个最小工作单元,承载部分数 ...

  10. Excel_单元格格式_查找替换、定位

    不重复! 显示格式:Ctrl+1 1,合并后居中,填充颜色,设置单元格边框,划斜线,格式刷(单击,双击) 2,单元格数字格式,格式不会改变值!自定义(编码规则) 4个 a :只显示星期:周+aaa:周 ...