板刷计划:ARC073

本文探讨了ATCODER算法竞赛中的几道题目,涉及背包问题的模拟和暴力枚举解法,以及贪心策略在解决最优化问题中的应用。对于背包问题,通过分类和排序实现暴力搜索;在二元组优化问题中,提出了确保最小值和最大值出现在不同集合的贪心策略,以及利用 multiset 进行动态调整的解决方案。此外,还提及了使用 dp 和线段树的潜在解法。
摘要由CSDN通过智能技术生成

前言:ATCODER的题是真的硬阿。思维量大…虐杀我这种无智商选手。

A.模拟,略.


B.暴力枚举

题目大意:

给你一个容量为w( w ≤ 1 e 9 w \leq 1e9 w1e9)的背包.现在有n( n ≤ 100 n \leq 100 n100)个物品,每个物品有体积 w i w_i wi 和 价值 v i ( w i , v i ≤ 1 e 9 ) v_i(w_i,v_i \leq 1e9) vi(wi,vi1e9).现在要让你最大化背包价值. 体积 w i ∈ [ w 1 , w 1 + 3 ] w_i \in [w_1,w_1+3] wi[w1,w1+3]

题目思路:

一个NPC问题。但是给定了体积的值域范围。不难想到对物品按体积大小分成4类再按价值从大到小排序.之后直接枚举每种体积的物品选多少个.跑个dfs即可。这样就包含了所有可能情况.

复杂度: O ( ( n 4 ) 4 ) O((\frac{n}{4})^4) O((4n)4)


C.究极思维,贪心.

题目大意:

给你n( n ≤ 1 e 5 n \leq 1e5 n1e5)个二元组 ( x i , y i ) (x_i,y_i) (xi,yi)。现在有两个集合A,B.你需要将所有二元组的其中一个放入集合A或B里。那么另外一个就会放入到另外一个集合里去。现在让你最小化下式:
( m a x A − m i n A ) ∗ ( m a x B − m i n B ) (max_A-min_A) * (max_B-min_B) (maxAminA)(maxBminB)

题目思路:

方法一 :正解

不难发现,二元组的最小值MI以及最大值MX一定存在于A,B集合中的一个。即一定会在上式中出现.

那么根据他们出现的情况讨论一下:

1.当 MI,MX 一个属于A,一个属于B.(具体是哪个不重要,因为对称)。假设: M I ∈ A , M X ∈ B MI \in A ,MX \in B MIAMXB

很显然,现在我们的策略就是:将每一个二元组中 较小的给A集合。 较大的给B集合.这样一定是最优的。

注:当时到这里我就卡住了,无法继续往下推了。。

2.当 MI,MX 同时属于A/B(具体是哪个不重要,因为对称)。假设: M I , M X ∈ A MI,MX\in A MI,MXA

由于 ( m a x A − m i n A ) (max_A-min_A) (maxAminA)已经确定,现在我们要做的事情就是最小化 ( m a x B − m i n B ) (max_B-min_B) (maxBminB).

这里的思路是:枚举 m i n B min_B minB. 假设最优解时 m i n B = x i min_B=x_i minB=xi,那么那些 【二元组较小值 小于 x i x_i xi】的二元组的较大值y要给B集合.

显然对x( x < y x < y x<y)从小到大排序,然后从小到大枚举x以及其后缀x就可以。为什么后缀全要选,因为我们人为规定了 x < y x < y x<y.所以后缀二元组中我们一定要选x.至于x的前缀二元组一定要选y,是因为必须要选才能满足 m i n B = x i min_B=x_i minB=xi

这里有个很简单的实现方式,用multiset,然后算完情况1后对二元组排序。直接模拟交换二元组即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define mp make_pair
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
pii a[maxn];
multiset<ll> A , B;
int main()
{
    ios::sync_with_stdio(false);
    int n; cin >> n;
    for (int i = 1 ; i <= n ; i++){
        cin >> a[i].first >> a[i].second;
        if (a[i].first > a[i].second) swap(a[i].first , a[i].second);
        A.insert(max(a[i].first,a[i].second));
        B.insert(min(a[i].first,a[i].second));
    }
    ll ans = (*(--A.end()) - *(A.begin())) * (*(--B.end()) - *(B.begin()));
    sort(a + 1 , a + 1 + n);
    for (int i = 1 ; i <= n ; i++){
        A.erase(A.find(a[i].second));
        B.erase(B.find(a[i].first));
        A.insert(a[i].first);
        B.insert(a[i].second);
        ans = min (ans , (*(--A.end()) - *(A.begin())) * (*(--B.end()) - *(B.begin())));
    }
    cout << ans << endl;
    return 0;
}

方法二 :随机化 + 贪心

离谱


D.dp + 线段树

待补.

题目大意:
题目思路:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值