AcWing 730. 机器人跳跃问题(二分 or 贪心)
题目链接:https://www.acwing.com/problem/content/732/
Description:
有n个点 要一步一步跳 设起点处初始能量为E 每跳一个点 E += E - q[i]
要求到达终点n并且在跳跃的过程中E >= 0 求最小初始值
Solution:
一看到1e5和单调性最值我就想写二分 简简单单的一个二分就写出来了 样例也过了 但是wa
感觉是爆了int 查看check式子中的公式 x += x - q[i] 感觉如果n=1e5 x = 5e2 那样就是x*2^n
这哪止是爆了int啊 明明就是爆了LL
所以我们不能一直累加 由公式E += E - q[i] 当E>maxH之后 E-q[i]始终为正数 即一定能到达终点
Code:
typedef long long LL;
int q[100010];
int n, mxh;
bool check(LL x)
{
for(int i = 1; i <= n; i++)
{
x += x - q[i];
if(x >= mxh) return true;
if(x < 0) return false;
}
return true;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
cin >> q[i], mxh = max(mxh, q[i]);
LL l = 0, r = mxh;
while(l < r)
{
LL mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << r << endl;
return 0;
}
某算法比赛? B - Erorr(二分 + 贪心)
Description:
给定int数组a 要求构造出一个严格上升int数组b 要求对于i = [1, n] abs(a[i] - b[i]) <= eps
求整数eps的最小值
Solution:
因为满足单调性 且时间复杂度大概就是卡在了nlgn 我首先就是想到二分的写法
要求构造严格上升数组b 那么b的前面的项越小越好 这是我们要贪心的点
namo 我们简单的判断一下 当a数组加上x都不如b的上一项的时候 证明x太大了 false 其余都贪
Code:
int n;
const int N = 2000010;
int a[N], b[N];
bool check(int x)
{
for(int i = 0; i < n; i++) b[i] = a[i];
b[0] -= x;
b[0] = max(1, b[0]);
for(int i = 1; i < n; i++)
{
if(b[i] + x <= b[i - 1]) return false; //最大的可能都不能构成上升 直接寄
if(b[i] - x > b[i - 1])
b[i] -= x; //贪心 前面的项越小越好
else
if(b[i] + x > b[i - 1])
b[i] = b[i - 1] + 1;//必定b[i] >= b[i - 1] + 1 贪
}
return true;
}
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> a[i];
int l = 0, r = 0x3f3f3f3f;
while(l < r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << r << '\n';
return 0;
}
蓝桥杯2019 修改数组(并查集维护数值)
Description:
给定长度为n的数组a a中可能有重复的整数存在
现在Bob要构造一个新的数组b
要求bi是a1~ai-1中的没出现过且大于等于bi的最小整数
5
2 1 1 3 4
2 1 3 4 5
Solution:
如果是暴力的写法 那就是去枚举i 用数组记录是否存在 然后用while为bi++ 很明显会超时
我们可以用并查集来维护这个数是否被输出过 若被输出过就输出这个数+1的数 以此类推
Code:
#include <bits/stdc++.h>
using namespace std;
int fa[1000010]; //维护当遇到i时该输出的值
int fd(int x)
{
if(fa[x] != x) fa[x] = fd(fa[x]);
return fa[x];
}
int main()
{
int n, x;
cin >> n;
for(int i = 1; i <= n; i++)
fa[i] = i;
for(int i = 1; i <= n; i++)
{
cin >> x;
int t1 = fd(x);
x = t1;
cout << x << ' ';
fa[x] = fd(t1 + 1); //下一次遇到x的时候要输出x+1
}
return 0;
}
ABC 238 E - Range Sums(并查集 区间合并)
题目链接:https://atcoder.jp/contests/abc238/tasks/abc238_e
Description:
有一个长度为n的未知数组 告诉你q次[l, r]的区间和 请问是否能够通过q个信息 得到位置数组和
Solution:
[1, 3] [3, 4]就可以得到[1, 4]
那[1, 3] [2, 4]则不可以得到[1, 4]
原理暂时还不是很清楚 先当做例题记下来
Code:
int fa[200010];
int n, m, l, r;
int fd(int x)
{
if(fa[x] != x) fa[x] = fd(fa[x]);
return fa[x];
}
int main()
{
cin >> n >> m;
for(int i = 0; i < 200010; i++) fa[i] = i;
while(m --)
{
cin >> l >> r;
fa[fd(l - 1)] = fd(r); //l-1到r是差分和
//将l1-1并入到r1 那么如果有[l2, r2]r2 == l1 - 1 那么这代表我们知道了[l2, r1]和
}
if(fd(0) == fd(n)) cout << "Yes\n"; //如果我们知道了[1, n]的区间和 那就成功了
else cout << "No\n";
return 0;
}
ABC 238 B - Piasa(模拟)
题目链接:https://atcoder.jp/contests/abc238/tasks/abc238_b
Description:
给定一个披萨 每次在12点方向切一刀 读入n个数 每次顺时针转动x度 再在12点方向切一刀
请问切完n+1刀后的相邻两刀之间最大角度
Solution:
模拟转动即可 然后用bool记录在角度x处切下一刀
Code:
map<int, bool> mp;
int main()
{
int n;
cin >> n;
mp[0] = true; //开始的时候切一刀
mp[360] = true; //0 和 360是重合的 只不过一个在起点一个在终点
int cur = 0;
for(int i = 1; i <= n; i++)
{
int x;
cin >> x;
cur = (cur + x) % 360;
mp[cur] = true; //n刀
}
vector<int> res;
for(auto x : mp)
res.push_back(x.first);
int ans = 0;
for(int i = 1; i < res.size(); i++)
ans = max(ans, res[i] - res[i - 1]); //枚举相邻两刀取max
cout << ans << endl;
return 0;
}
明天早上上一节高数
补高数作业
下午上一节物理 上一节二分
晚上做二分题单 kuangbin搜索一题
做天际线问题 https://leetcode-cn.com/problems/the-skyline-problem/
晚上背单词 刷水题