珍珠

题意

一共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. PWA 学习笔记

    深入学习网址:https://developer.mozilla.org/zh-CN/docs/Web/Progressive_web_apps 一. 基本介绍 1. 渐进式:适用所有浏览器,因为它是 ...

  2. TCP协议可靠性是如何保证之滑动窗口,超时重发,序列号确认应答信号

    原创文章首发于公众号:「码农富哥」,欢迎收藏和关注,如转载请注明出处! TCP 是一种提供可靠性交付的协议. 也就是说,通过 TCP 连接传输的数据,无差错.不丢失.不重复.并且按序到达. 但是在网络 ...

  3. mybatis缓存,包含一级缓存与二级缓存,包括ehcache二级缓存

    一,引言 首先我们要明白一点,缓存所做的一切都是为了提高性能.明白了这一点下面我们开始进入正题. 二,mybatis缓存概要 ①.mybatis的缓存有两种,分别是一级缓存和二级缓存.两者都属于查询缓 ...

  4. React中ref的使用

    直接获取DOM元素时使用的,一般情况下尽量不要使用ref

  5. CentOS 7.6下安装 NVM 管理不同版本的 Node.js

    学习网站:https://www.linuxidc.com/Linux/2019-10/160918.htm

  6. 小白学 Python 数据分析(9):Pandas (八)数据预处理(2)

    人生苦短,我用 Python 前文传送门: 小白学 Python 数据分析(1):数据分析基础 小白学 Python 数据分析(2):Pandas (一)概述 小白学 Python 数据分析(3):P ...

  7. 显示二维码-智能TFT模块

    应用范例: 使用 TOPWAY Smart LCD (HMT050CC-C) 显示二维码 第一步 建立工程 ① 开 Editor 软件, 点击菜单栏建立新工程File --> New Proje ...

  8. js面试相关

    〇,字符串,数值,数组的转化 (0)检测数据类型 参考连接:http://www.cnblogs.com/onepixel/p/5126046.html 1,, typeof 操作符 :  能检测到( ...

  9. C#设计模式学习笔记:(16)观察者模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7928521.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第四个模式--观 ...

  10. Golang中的Slice与数组

    1.Golang中的数组 数组是一种具有固定长度的基本数据结构,在golang中与C语言一样数组一旦创建了它的长度就不允许改变,数组的空余位置用0填补,不允许数组越界. 数组的一些基本操作: 1.创建 ...