天梯算法Day1整理

Nanami and Arithmetic Sequence

题面

思路

炸鱼题

只有n=1的时候,只有一个等差数列;

其余时候,都是都有无数个等差数列。

代码

#include <iostream>
using namespace std;

int  main() {
	int t, n;
	cin >> t;
	while (t--) {
		cin >> n;
		if (n == 1)
			cout << "1\n";
		else
			cout << "-1\n";
	}
	return 0;
}

珠宝价值

题面

思路

浓缩一下,题目是在求数组的连续子数组最大和。 

即一个很经典的问题——最大子段和

这题在洛谷上也有,链接在下,感兴趣的朋友可以一试。(注意数据范围的区别)

最大子段和 - 洛谷
 

本题采用动态规划来解

设dp[i]表示[0,i]闭区间以i为右边界的最大子段和(我们并不关注左边界的位置)

最开始有dp[0] = v[0]

由[0,i]推[0,i+1]时,如果dp[i]+v[i+1]>dp[i],则说明加上该值后总和变大,所以需dp[i+1]=dp[i]+v[i+1]。否则,从头开始计和,dp[i+1]=v[i+1]。

最后找到dp数组中的最大值即可

代码

#include <iostream>
using namespace std;

#define MAXN 10005

int v[MAXN];
int dp[MAXN];

int main() {
	int n;
	cin >> n;
	int i = 0;
	while (n--) {
		cin >> v[i];
		i++;
	}
	dp[0] = v[0];
	for (int j = 0; j < i - 1; j++) {
		if (dp[j] + v[j + 1] > v[j + 1]) {//条件里也可以是dp[j]>0
			dp[j + 1] = dp[j] + v[j + 1];
		} else {
			dp[j + 1] = v[j + 1];
		}
	}

	int maxv = -1e9;

	for (int j = 0; j < i; j++) {
		if (dp[j] > maxv)
			maxv = dp[j];
	}
	cout << maxv << endl;
	return 0;
}

Nanami and Toys Buying Problem

题面

思路

每个a[i]最多只被取一次,最多只有一个b[i]会被取2次以上。

枚举被多次取的玩具,设当前取的为b[i],那么对于行a来说,a[j]>b[i]时才有取的必要,否则不用取。(当j<i时,需要先取出a[i]才能取b[i])

可以按a的大小排序,枚举b,结合二分查找得到j。

(这里其实是在找满足a[j]>=b[i]的最小值)

代码

先放一份能反映基础思路,但TLE了的代码

#include <iostream>
using namespace std;

const int  maxn  = 2e5 + 5;

int a[maxn], b[maxn];

int main() {
	int t;
	cin >> t;
	while (t--) {
		int n, k;
		cin >> n >> k;
		int k2 = k;
		long long ans = 0;
		for (int i = 0; i < n; i++)
			cin >> a[i];
		for (int i = 0; i < n; i++)
			cin >> b[i];
		int i, j;
		for (i = 0; i < n - 1; i++)
			for (j = 0; j < n - 1 - i; j++)
				if (a[j] < a[j + 1]) {
					swap(a[j], a[j + 1]);
					swap(b[j], b[j + 1]);
				}


		for (int i = 0; i < n; i++) {
			k = k2;
			long long currentans = 0;
			if (k >= 1) {
				currentans += a[i];
				k--;
			}
			int maxj = -1;
			for (int j = 0; j < n; j++) {
				if (j != i) {
					if (a[j] > b[i] && k > 0) {
						currentans += a[j];
						k--;
						maxj = j;
					}
				} else
					continue;
			}
			if (k > 0)
				currentans += 1ll * k * b[i];
			if (currentans > ans)
				ans = currentans;
		}
		cout << ans << endl;
	}

	return 0;
}

再放一份优化过的代码,使用二分+前缀和

#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 2e5 + 5;

int T, n, k;

int a[maxn], b[maxn], s[maxn];

long long preSum[maxn];

long long spe1()
{
	sort(a + 1, a + n + 1);
	return a[n];
}

long long ans, sum;

int main()
{
	cin >> T;
	for (int rt = 1; rt <= T; rt++)
	{
		ans = 0;
		cin >> n >> k;
		for (int i = 1; i <= n; i++) {cin >> a[i]; s[i] = a[i];}
		for (int i = 1; i <= n; i++) cin >> b[i];
		if (k == 0)
		{
			cout << 0 << '\n';
			continue;
		}
		if (k == 1) 
		{
			cout << spe1() << '\n';
			continue;
		}
		sort(s + 1, s + n + 1);
		for (int i = 1; i <= n; i++) preSum[i] = preSum[i - 1] + s[i];
		int res = k - 1;
		for (int i = 1; i <= n; i++) 
		{
			sum = a[i];
			//cout << sum << '\n';
			int num = n + 1 - (upper_bound(s + 1, s + n + 1, b[i]) - s);
			if (a[i] <= b[i]) 
			{
				if (res <= num) sum += preSum[n] - preSum[n - res];
				else sum += preSum[n] - preSum[n - num] + 1ll * (res - num) * b[i];
			} else {
				
				if (res < num - 1) 
				{
					int lowPos = lower_bound(s + 1, s + n + 1, a[i]) - s;
					if (a[i] >= s[n - res + 1] && lowPos >= n - res + 1)
					{
						sum += preSum[n] - preSum[n - res - 1] - a[i];
					}
					else {
						sum += preSum[n] - preSum[n - res];
					}
				}
				else sum += preSum[n] - preSum[n - num] - a[i] + 1ll * (res - (num - 1)) * b[i];
			}
			ans = max(ans, sum);
			//cout << sum << '\n' << '\n';
		}
		cout << ans << '\n';
	}
	return 0;
}

类似题目(某厂面试题)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值