鸡鸭分类问题
题目
农场有n
只鸡鸭排为一个队伍,鸡用“C”
表示,鸭用“D”
表示。当鸡鸭挨着时会产生矛盾。需要对所排的队伍进行调整,使鸡鸭各在一边。每次调整只能让相邻的鸡和鸭交换位置,现在需要尽快完成队伍调整,你需要计算出最少需要调整多少次可以让上述情况最少。例如:CCDCC->CCCDC->CCCCD
这样就能使之前的两处鸡鸭相邻变为一处鸡鸭相邻,需要调整队形两次。
输入描述:
输入一个长度为N
,且只包含C
和D
的非空字符串。
输出描述:
使得最后仅有一对鸡鸭相邻,最少的交换次数
样例:
CCDCC >--------------------------------------------------< 2
解析
枚举两种最终状态,CDCCC
,要么变成DCCCC
,要么变成CCCCD
;
对于其中任意一种状态的每一个需要移动的元素,只需要看一下移动的方向上有多少个不一样的元素,然后累加起来就行了。
#include <bits/stdc++.h>
int main()
{
for (std::string str; std::cin >> str; ) {
std::vector<int> c(str.size(), 0), d(c);
for (unsigned i = 0; i < c.size(); c[i] = (str[i] == 'C') + (i ? c[i - 1] : 0), ++i) {}
for (unsigned i = 0; i < d.size(); d[i] = (str[i] == 'D') + (i ? d[i - 1] : 0), ++i) {}
int ansC = 0, ansD = 0;
for (unsigned i = 0; i < c.size(); ansC += str[i] == 'D' ? c[i] : 0, ++i) {}
for (unsigned i = 0; i < d.size(); ansD += str[i] == 'C' ? d[i] : 0, ++i) {}
std::cout << std::min(ansC, ansD) << std::endl;
}
return 0;
}
比特币最佳买卖时机
题目
给定一个正整数数组,它的第 i
个元素是比特币第 i
天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一次),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入比特币前卖出。
输入描述:
正整数数组,为以空格分隔的n
个正整数
输出描述:
最大利润
样例:
7 1 5 3 6 4 >--------------------------------------------------< 5
解析
在序列中找到一个差值最大的有序偶 ;
的做法应该都会。这里讲一下 。
对于第i
个位置上的元素,我们只需要知道区间[0, i - 1]
最小值,就可以得出第二个数的位置为i
的最大差值有序偶,枚举i
就可以得出答案;而区间[0, i - 1]
最小值可以预处理出来。
因此总体时间复杂度为 。
#include <bits/stdc++.h>
int main()
{
std::string arrString;
std::getline(std::cin, arrString);
std::vector<int> arr, dp;
std::stringstream sin(arrString);
for (int x; sin >> x; arr.emplace_back(x)) {}
dp.resize(arr.size(), arr[0]);
for (unsigned i = 1; i < dp.size(); dp[i] = std::min(dp[i - 1], arr[i]), ++i) {}
int ans = 0;
for (unsigned i = dp.size() - 1; i > 0; ans = std::max(ans, arr[i] - dp[i - 1]), --i) {}
std::cout << ans << std::endl;
return 0;
}
爱吃喵粮的小招喵
题目
小招喵喜欢吃喵粮。这里有 N
堆喵粮,第 i
堆中有 p[i]
粒喵粮。喵主人离开了,将在 H
小时后回来。
小招喵可以决定她吃喵粮的速度 K
(单位:粒/小时)。每个小时,她将会选择一堆喵粮,从中吃掉 K
粒。如果这堆喵粮少于 K
粒,她将吃掉这堆的所有喵粮,然后这一小时内不会再吃更多的喵粮。
小招喵喜欢慢慢吃,但仍然想在喵主人回来前吃掉所有的喵粮。
返回她可以在 H
小时内吃掉所有喵粮的最小速度 K
(K
为整数)。
输入描述:
第一行输入为喵粮数组,以空格分隔的N
个整数
第二行输入为H
小时数
输出描述:
最小速度K
样例:
3 6 7 11 8 >--------------------------------------------------< 4
解析
二分答案,求下界。
要注意的是,H
一定大于N
,不然,多快的速度都不可能完成任务。题目中没有说明,这里应该强调一下。
#include <bits/stdc++.h>
int main()
{
std::string pString;
std::getline(std::cin, pString);
int H;
std::cin >> H;
std::vector<int> p;
[] (const std::string & str, std::vector<int> & vec) {
std::stringstream sin(str);
for (int x; sin >> x; vec.emplace_back(x)) {}
} (pString, p);
int l = 1, r = *std::max_element(std::begin(p), std::end(p));
while (l < r) {
int mid = l + (r - l) / 2;
if ([&] (int k) {
return std::accumulate(std::begin(p), std::end(p), 0, [k] (int init, int s) {
return init + std::ceil(s * 1.0 / k);
}) <= H;
} (mid))
r = mid;
else
l = mid + 1;
}
std::cout << l << std::endl;
return 0;
}
推倒吧骨牌
题目
有一排长度为N的骨牌,初始状态下所有的骨牌都是站立状态,如下图所示。
现在我们选定其中几块骨牌,并指定其方向进行推倒,如下图所示。
如果用字符的形式定义,则上述过程可以描述为:
输入".L.R...LR....L."
,对应的输出为"LL.RR.LLRRRLLL."
。
其中L
表示向左倒,R
表示向右倒,.
表示任然为站立状态。
输入描述:
输入为一个长度不超过1000的,仅包含‘L’
,‘R’
,‘.’
的字符串
输出描述:
根据输入,输出一个仅由‘L’
,‘R’
,‘.’
组成的结果字符串
样例:
.L.R...LR....L. >--------------------------------------------------< LL.RR.LLRRRLLL.
解析
模拟就好了,只有R...L
这种情况会往中间挤,处理下就行了。
#include <bits/stdc++.h>
int main()
{
for (std::string str; std::cin >> str; ) {
bool LorR = false;
std::string::iterator pos = std::begin(str), pre = pos;
for (;;) {
auto it = std::find_if(pre, std::end(str), [] (const char c) {
return c == 'R' || c == 'L';
});
if (it == std::end(str))
break;
if (*it == 'R') {
if (LorR) std::fill(pos, it, 'R');
LorR = true;
pos = it;
} else {
if (LorR) {
std::fill(pos + 1, pos + (it - pos + 1) / 2, 'R');
std::fill(pos + (it - pos + 1) / 2, it, 'L');
if ((it - pos - 1) & 1) *(pos + (it - pos) / 2) = '.';
LorR = false;
} else {
std::fill(pre, it, 'L');
}
}
pre = it + 1;
}
if (LorR) std::fill(pos, std::end(str), 'R');
std::cout << str << std::endl;
}
return 0;
}
重叠的装饰
题目
我们部门需要装饰墙,但是墙非常非常的长,有一千万米。我们会按顺序贴很多海报在上面,这些海报相互之间会重叠,请问下,最后还能看到哪些?(只看到一部分也算)
输入描述:
N
表示N
张海报
接下来每一行代表海报的左右边界(上下默认全满),Li
,Ri
,均为整数,大于0,小于一千万。海报按输入顺序张贴。
输出描述:
有多少张海报是可见的
样例:
5 1 4 2 6 8 10 3 4 7 10 >--------------------------------------------------< 4
解析
不考虑数据范围,模拟就可以了;
数据范围一大,就需要一些技巧来模拟,这里用到的技巧是线段树维护区间更新加上区间离散化。
其实这个题是POJ - 2528原题。
但是,这个题的数据不对,只能过80%的数据,我把网上其他大牛的代码交了下也是只能过80%的数据,而且,不过的那组数据我弄下来看看,也不对劲。
所以,我写的下面这个代码可能过不了这个题,但是确实是正确的。
#include <bits/stdc++.h>
struct SegmentTree;
typedef struct std::shared_ptr<SegmentTree> pSegmentTree;
struct SegmentTree
{
public:
void update(int lhs, int rhs, int l, int r, int c);
unsigned query(int lhs, int rhs);
static void build(pSegmentTree & root, int lhs, int rhs);
public:
pSegmentTree lchs = nullptr, rchs = nullptr;
int color = 0;
private:
void query_aux(int lhs, int rhs, std::set<int> & colors);
};
void SegmentTree::build(pSegmentTree & root, int lhs, int rhs)
{
root = std::make_shared<SegmentTree>();
if (lhs == rhs) return ;
int mid = (lhs + rhs) >> 1;
build(root->lchs, lhs, mid);
build(root->rchs, mid + 1, rhs);
}
void SegmentTree::update(int lhs, int rhs, int l, int r, int c)
{
if (lhs == l && rhs == r) {
color = c;
return ;
}
if (color) {
if (lchs) lchs->color = color;
if (rchs) rchs->color = color;
color = 0;
}
int mid = (lhs + rhs) >> 1;
if (r <= mid) lchs->update(lhs, mid, l, r, c);
else if (mid + 1 <= l) rchs->update(mid + 1, rhs, l, r, c);
else {
lchs->update(lhs, mid, l, mid, c);
rchs->update(mid + 1, rhs, mid + 1, r, c);
}
}
unsigned SegmentTree::query(int lhs, int rhs)
{
std::set<int> colors;
query_aux(lhs, rhs, colors);
return colors.size();
}
void SegmentTree::query_aux(int lhs, int rhs, std::set<int> &colors)
{
if (color) {
colors.insert(color);
return ;
}
if (lhs == rhs) return ;
int mid = (lhs + rhs) >> 1;
lchs->query_aux(lhs, mid, colors);
rchs->query_aux(mid + 1, rhs, colors);
}
int main()
{
for (int n; EOF != std::scanf("%d", &n); ) {
typedef std::pair<int, int> Line;
std::vector<Line> lines;
for (int i = 0, x, y; i < n; std::scanf("%d%d", &x, &y), lines.emplace_back(x, y), ++i) {}
std::vector<int> digits;
for (int i = 0; i < n; digits.emplace_back(lines[i].first), digits.emplace_back(lines[i].second), ++i) {}
std::sort(std::begin(digits), std::end(digits));
for (unsigned i = 1, top = digits.size(); i < top; ++i) if (digits[i] - digits[i - 1] > 1)
digits.emplace_back(digits[i] - 1);
std::sort(std::begin(digits), std::end(digits));
digits.erase(std::unique(std::begin(digits), std::end(digits)), std::end(digits));
std::shared_ptr<SegmentTree> root = nullptr;
SegmentTree::build(root, 1, (int)digits.size());
for (const auto & line : lines) {
static int color = 1;
root->update(1, (int)digits.size(),
std::lower_bound(std::begin(digits), std::end(digits), line.first) - std::begin(digits) + 1,
std::lower_bound(std::begin(digits), std::end(digits), line.second) - std::begin(digits) + 1,
color++);
}
std::printf("%u\n", root->query(1, (int)digits.size()));
}
return 0;
}