小记_AtCoder Beginner Contest 336

A - Long Loong

输入一个正整数 n n n,输出一个字符串:‘L’ + n n n 个 ‘o’ + ‘n’ + ‘g’。

解:

#include <bits/stdc++.h>

using namespace std;

int main() {
	long long a;
	cin >> a;
	printf("L");
	for (int i = 0; i < a; i++)
	    printf("o");
	printf("ng\n");
	return 0;
}

B - CTZ

输入一个数正整数 n n n, 输出这个数的二进制表示中有多少个后缀 ‘0’。

解:

#include <bits/stdc++.h>

using namespace std;

int main() {
	long long a;
	cin >> a;
	long long ans = 0;
	while (a) {
		if (a % 2 == 0) {
	    	ans++; 
	    	a /= 2;
		}
		else break;
	}
	printf("%lld\n", ans);
	return 0;
}

C - Even Digits

输入一个正整数 n n n,输出在(0,2,4,6,8,20,22,24,26,28,40,…)进制下第 n n n 个数是多少。从 0 0 0 开始计数。

解:

只需将 0, 1, 2, 3, 4替换成 0, 2, 4, 6, 8。

#include <bits/stdc++.h>

using namespace std;
int q[100], idx;
int main() {
	long long a;
	cin >> a;
	a--;//从0开始计数,所以先减去1
	long long ans = 0;
	if (!a) printf("0");// 再特判
	while (a) {
		q[++idx] = (a % 5) * 2;
		a /= 5;
	}
	for (int i = idx; i >= 1; i--)
	    printf("%d", q[i]);
	return 0;
}

D - Pyramid

输入一个正整数数 n n n n n n 个正整数,只能进行以下两种操作,操作次数不限:
1、 删除第一个数或者删除最后一个数。
2、 将一个位置的数减 1。
问能构成的最高的金字塔型有多高。
金字塔型即:1、1 2 1、1 2 3 2 1、1 2 3 4 3 2 1,高度分别是 1,2,3,4。

解:

动态规划的思想,先考虑左半部分,假设循环枚举到第 i i i 个位置,如果前面一个位置能达到的高度为 m m m,则当前位置能达到的最高高度为 m i n ( a [ i ] , m + 1 ) min(a[i], m + 1) min(a[i],m+1)。因为:

1、如果前面一个位置能达到的最高高度大于第 i i i 个位置的数 a [ i ] a[i] a[i],那么当前最大高度只能达到 a [ i ] a[i] a[i] 。因为只减不加,所以最大高度为 a [ i ] a[i] a[i];再者可以通过将前面的数全部减 1 1 1 使得前面的数减小到 a[i] - 1,使得 a [ i ] a[i] a[i] 这个高度能达到。

2、如果当前位置比前面一个位置能达到的最高高度大,由于要维持金字塔型,前面的最大高度为 m m m,所以只能将当前的数变为 m + 1 m+1 m+1 来达到最大高度。
综上即是 m i n ( a [ i ] , m + 1 ) min(a[i], m + 1) min(a[i],m+1) 的由来。
同理再考虑金字塔的右半部分,可得出第 i i i 个位置左半部分和右半部分能达到的最大高度,设为 l [ i ] , r [ i ] l[i], r[i] l[i],r[i],则以当前第 i i i 个位置为塔尖的金字塔最大高度为 m i n ( l [ i ] , r [ i ] ) min(l[i], r[i]) min(l[i],r[i])。枚举每一个位置作为塔尖,即可得出答案。

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int a[N], n;
int l[N], r[N];
int ans;

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++)
	    scanf("%d", &a[i]);
	for (int i = 1; i <= n; i++)
	    l[i] = min(a[i], l[i-1] + 1);
	for (int i = n; i >= 1; i--)
	    r[i] = min(a[i], r[i+1] + 1);
	for (int i = 1; i <= n; i++)
	    ans = max(ans, min(l[i], r[i]));
	printf("%d\n", ans);
	return 0;
}

拓展:

可以为题目进行拓展,比如将操作 1 1 1 改成可以删除任一位置的数;达到最大高度的同时将操作数降到最少。

//修改操作 1
#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int a[N], n;
int l[N], r[N];
int q[N], tt;
int ans;

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++)
	    scanf("%d", &a[i]);
	for (int i = 1; i <= n; i++) {
		while (tt && a[q[tt]] >= a[i]) tt--;
		if (tt) l[i] = l[q[tt]] + min(i - q[tt], a[i] - a[q[tt]]);
		else l[i] = min(a[i], i);
		q[++tt] = i;
	}
	tt = 0;
	for (int i = n; i >= 1; i--) {
		while (tt && a[q[tt]] >= a[i]) tt--;
		if (tt) r[i] = r[q[tt]] + min(q[tt] - i, a[i] - a[q[tt]]);
		else r[i] = min(a[i], n - i + 1);
		q[++tt] = i;
	}   
	for (int i = 1; i <= n; i++)
	    ans = max(ans, min(l[i], r[i]));
	printf("%d\n", ans);
	return 0;
}
  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值