Codeforces Round #809 (Div. 2) C-D1

这篇博客探讨了Codeforces平台上的两道算法竞赛题目。第一题针对奇数和偶数情况分析了找到最大cool数的方法,通过动态规划求解。第二题涉及寻找数组中最大值与最小值之差的最小值,采用动态规划和区间搜索策略。文章提供了详细的解题思路和官方解答。
摘要由CSDN通过智能技术生成

C:我们可以发现对于n为奇数的情况,只有一种可能,那就是2,4,---n-1为cool,所以直接处理就好,对于n为偶数来说比较困难,但通过其给的数据可以发现我们至多存在一个地方在两个cool中有两个不为cool的地方

 

(来自codeforces #809 C)

以给的数据为例子 在第2个和第4个之间有连续两个不为cool的地方,我们将其左右移动就可以找到规律:只能在首位为奇数的连续两个才可以满足最大的cool数,所以接下来只要将这两边分为两段,找最大就好了,可能不太清楚

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define int long long
const int maxn = 2e5 + 10;
int a[maxn], n, m;
int b[maxn];//代表将i维护位cool的花费
int dpfroce[maxn], dpback[maxn];
void solve()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	if (n % 2)
	{
		int ans = 0;
		for (int i = 2; i <= n; i += 2)
		{
			if (a[i] > a[i - 1] && a[i] > a[i + 1])
				ans+= 0;
			else if (a[i] <= a[i - 1] && a[i] > a[i + 1])
			{
				ans+= a[i - 1] - a[i] + 1;
			}
			else if (a[i] > a[i - 1] && a[i] <= a[i + 1])
			{
				ans+= a[i + 1] - a[i] + 1;
			}
			else
			{
				ans+= max(a[i - 1] - a[i] + 1, a[i + 1] - a[i] + 1);
			}
		}
		cout << ans << endl;
		return;
	}
	else
	{
		for (int i = 2; i <n; i++)
		{
			if (a[i] > a[i - 1] && a[i] > a[i + 1])
				b[i] = 0;
			else if (a[i] <= a[i - 1] && a[i] > a[i + 1])
			{
				b[i] = a[i - 1] - a[i] + 1;
			}
			else if(a[i]>a[i-1]&&a[i]<=a[i+1])
			{
				b[i] = a[i + 1] - a[i] + 1;
			}
			else
			{
				b[i] = max(a[i - 1] - a[i] + 1, a[i + 1] - a[i] + 1);
			}
		}
		for (int i = 1; i <= n + 1; i++)
			dpback[i] = dpfroce[i] = 0;
		for (int i = n - 1; i >= 2; i--)
		{//代表将i后面均维护位最大cool的情况
			dpback[i] = dpback[i + 2] + b[i];	
		}
		for (int i = 2; i <= n - 1; i++)
		{
			dpfroce[i] = dpfroce[i - 2] + b[i];
		}
		int ans =min(dpback[3],dpfroce[n-2]);
		int now = 0;
		for (int i = 3; i <n - 1; i += 2)
		{
			ans = min(ans, dpfroce[i - 1] + dpback[i +2]);
		}
		cout << ans << endl;
	}
}
signed main()
{
	int t;
	cin >> t;
	while (t--)
		solve();
}

D1:其实刚刚开始看的时候我是想每次变动最大值,来更新答案的,后来发现这样做可能有点不太好处理就没写了,这里给官方答案的一个解释:

首先是最大值-最小值,我们需要找到最大和最小值,这类似找一段区间的那种感觉,我们可以像处理找一段合法区间问题那样,将左端点固定,枚举右端点这类做法,我们可以枚举最小值,并在保持最小值的基础上找靠近最小值的最大值来更新答案

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
#define int long long
const int maxn = 3e3 + 10;
int a[maxn],n,k;
void solve()
{
	cin >> n >> k;
	map<int, int>m;
	vector<int>v;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		for (int j = 1; j <= k; j++)
		{
			if (a[i] / j <= a[1] && m.count(a[i] / j) == 0)
			{
				m[a[i] / j] = 1;
				v.push_back(a[i] / j);
			}
		}
	}
	int ans = 1e18;
	for (auto x : v)
	{
		int maxx = x;
		for (int i = 1; i <= n; i++)
		{
			int p = min(k, (x ? (a[i] /x) : k));//保证了a[i]/p是最接近x的
			maxx = max(maxx, a[i] / p);
		}
		ans = min(ans, maxx - x);
	}
	cout << ans << endl;

}
signed main()
{
	int t;
	cin >> t;
	while (t--)
		solve();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值