机器人正在玩一个古老的基于 DOS 的游戏。
游戏中有 N+1 座建筑——从 0 到 N 编号,从左到右排列。
编号为 0 的建筑高度为 0 个单位,编号为 i 的建筑高度为 H(i) 个单位。
起初,机器人在编号为 0 的建筑处。
每一步,它跳到下一个(右边)建筑。
假设机器人在第 k 个建筑,且它现在的能量值是 E,下一步它将跳到第 k+1 个建筑。
如果 H(k+1)>E,那么机器人就失去 H(k+1)−E 的能量值,否则它将得到 E−H(k+1) 的能量值。
游戏目标是到达第 N 个建筑,在这个过程中能量值不能为负数个单位。
现在的问题是机器人至少以多少能量值开始游戏,才可以保证成功完成游戏?
输入格式
第一行输入整数 N。
第二行是 N 个空格分隔的整数,H(1),H(2),…,H(N) 代表建筑物的高度。
输出格式
输出一个整数,表示所需的最少单位的初始能量值上取整后的结果。
数据范围
1≤N,H(i)≤105
输入样例1:
5
3 4 3 2 4
输出样例1:
4
输入样例2:
3
4 4 4
输出样例2:
4
输入样例3:
3
1 6 4
输出样例3:
3
解题思路
二分能量值,找到一个最小的符合要求的最小值即可
#include
using namespace std;
const int N = 1e5 + 10;
int n;
int f[N];
bool check(int mid) {
for(int i = 0; i < n; i ++ ) {
mid = mid * 2 - f[i];
if(mid > 1e5) return true;
if(mid < 0) return false;
}
return true;
}
int main() {
cin >> n;
for(int i = 0; i < n; i ++ ) cin >> f[i];
int l = 0, r = N;
while(l < r) {
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
四平方和定理,又称为拉格朗日定理:
每个正整数都可以表示为至多 4 个正整数的平方和。
如果把 0 包括进去,就正好可以表示为 4 个数的平方和。
比如:
对于一个给定的正整数,可能存在多种平方和的表示法。
要求你对 4 个数排序:
0≤a≤b≤c≤d
并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。
输入格式
输入一个正整数 N。
输出格式
输出4个非负整数,按从小到大排序,中间用空格分开。
数据范围
0
6
输入样例:
5
输出样例:
0 0 1 2
解题思路
直接暴力,四层循环,数据范围是 5∗106 会直接超时
优化方式,先枚举 c 和 d,将结果存储下来,再枚举 a 和 b,查看是否能够找到符合条件的 c 和 d,时间复杂度直接减半
用空间替换时间!
#include
#include
using namespace std;
const int N = 2500010;
struct Sum{
int sum, c, d;
bool operator < (const Sum &t) const {
if(sum != t.sum) return sum < t.sum;
if(c != t.c) return c < t.c;
return d < t.d;
}
}sum[N];
int main() {
int n, m;
cin >> n;
//先枚举c和d
for(int c = 0; c * c <= n; c ++ ) {
for(int d = c; c * c + d * d <= n; d ++ ) {
sum[m ++ ] = {c * c + d * d, c, d};
}
}
//排序
sort(sum, sum + m);
//再枚举a和b
for(int a = 0; a * a <= n; a ++ ) {
for(int b = 0; b * b + a * a <= n; b ++ ) {
int t = n - a * a - b * b;
int l = 0, r = m - 1;
while(l < r) {
int mid = l + r >> 1;
if(sum[mid].sum >= t) r = mid;
else l = mid + 1;
}
if(sum[l].sum == t) {
cout << a << ' ' << b << ' ' << sum[l].c << ' ' << sum[l].d << endl;
return 0;
}
}
}
return 0;
}
儿童节那天有 K 位小朋友到小明家做客。
小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 N 块巧克力,其中第 i 块是 Hi×Wi 的方格组成的长方形。
为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。
切出的巧克力需要满足:
形状是正方形,边长是整数大小相同
例如一块 6×5 的巧克力可以切出 6 块 2×2 的巧克力或者 2 块 3×3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含两个整数 Hi 和 Wi。
输入保证每位小朋友至少能获得一块 1×1 的巧克力。
输出格式
输出切出的正方形巧克力最大可能的边长。
数据范围
1≤N,K≤105, 1≤Hi,Wi≤105
输入样例:
2 10
6 5
5 6
输出样例:
2
解题思路
二分满足条件的最大边长!!!
二分的时候又出错了…
二分条件可以查看一下这篇博客:https://www.acwing.com/blog/content/307/
写的很好!
#include
using namespace std;
const int N = 1e5 + 10;
int n, k;
int h[N], w[N];
bool check(int mid) {
int sum = 0;
for(int i = 0; i < n; i ++ ) {
sum += (h[i] / mid) * (w[i] / mid);
}
if(sum >= k) return true;
return false;
}
int main() {
cin >> n >> k;
int res = 0x3f3f3f3f;
for(int i = 0; i < n; i ++ ) {
cin >> h[i] >> w[i];
// res = min(h[i], res);
// res = min(w[i], res);
}
//二分查找边长
//这里不能使用最小值,因为有的比较小的巧克力是可以不选择的!!!
// int l = 0, r = res;
int l = 0, r = N;
while(l < r) {
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
return 0;
}
地图上有 N 个目标,用整数 Xi,Yi 表示目标在地图上的位置,每个目标都有一个价值 Wi。
注意:不同目标可能在同一位置。
现在有一种新型的激光炸弹,可以摧毁一个包含 R×R 个位置的正方形内的所有目标。
激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆炸范围,即那个正方形的边必须和 x,y 轴平行。
求一颗炸弹最多能炸掉地图上总价值为多少的目标。
输入格式
第一行输入正整数 N 和 R,分别代表地图上的目标数目和正方形包含的横纵位置数量,数据用空格隔开。
接下来 N 行,每行输入一组数据,每组数据包括三个整数 Xi,Yi,Wi,分别代表目标的 x 坐标,y 坐标和价值,数据用空格隔开。
输出格式
输出一个正整数,代表一颗炸弹最多能炸掉地图上目标的总价值数目。
数据范围
0≤R≤109
00≤Xi,Yi≤5000
0≤Wi≤1000
输入样例:
2 1
0 0 1
1 1 1
输出样例:
1
感觉范围有点问题…
#include
using namespace std;
const int N = 5010;
int n, r;
int s[N][N];
int main() {
cin >> n >> r;
r = min(5001, r);
int l = 0;
int m = 0;
l = m = r;
for(int i = 0; i < n; i ++ ) {
int x, y, w;
cin >> x >> y >> w;
s[x + 1][y + 1] += w;
l = max(l, x + 1);
m = max(m, y + 1);
}
for(int i = 1; i <= l; i ++ ) {
for(int j = 1; j <= m; j ++ ) {
s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
}
}
int ans = 0;
for(int i = r; i <= l; i ++ ) {
for(int j = r; j <= m; j ++ ) {
ans = max(ans, s[i][j] - s[i - r][j] - s[i][j - r] + s[i - r][j - r]);
}
}
cout << ans << endl;
return 0;
}
给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K 倍区间。
你能求出数列中总共有多少个 K 倍区间吗?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含一个整数 Ai。
输出格式
输出一个整数,代表 K 倍区间的数目。
数据范围
1≤N,K≤100000, 1≤Ai≤100000
输入样例:
5 2
1
2
3
4
5
输出样例:
6
#include
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, k;
//这里要用ll,Ai相加后可能会爆int
ll s[N];
ll p[N];
int main() {
cin >> n >> k;
for(int i = 1; i <= n; i ++ ) {
cin >> s[i];
s[i] += s[i - 1];
}
ll ans = 0;
p[0] = 1;
for(int i = 1; i <= n; i ++ ) {
//这里先加后更新
//原因:
//对于p[0]来说存在一个就符合条件,对于p[1]来说要存在两个才能符合条件
//因此初始化p[0] = 1,然后先加够更新
ans += p[s[i] % k];
p[s[i] % k] ++ ;
}
cout << ans << endl;
}