20250724
贪心世界第一好玩!
CF1601D Difficult Mountain
神秘贪心
思路
发现当 \(a < d\) 时没有任何影响,所以将所有 \(a < d\) 的登山者全部放到前面。
然后以 \(\max(a_{i},s_{i})\) 为第一关键字, \(s_{i}\) 为第二关键字从小到大排序。
然后依次枚举,能选就选,就是最优答案。
证明:
按 \(\max(a,s)=a/s\) 分类讨论。
-
\(\max_{i}=a_{i},\max_{j}=a_{j}\) ,不妨设 \(a_{i}<a_{j}\) ,如果 \(j\) 先上, \(i\) 一定上不去,所以不如让 \(i\) 先去试试。
-
\(\max_{i}=a_{i},\max_{j}=s_{j}\) ,如果 \(a_{i}>s_{j}\) 则同上, \(i\) 先上, \(j\) 一定上不去,所以不如让 \(j\) 先去试试。 如果 \(a_{i}\le s_{j}\) ,那么 \(i\) 先上对 \(j\) 显然不会有影响。
-
\(\max_{i}=s_{i},\max_{j}=s_{j}\) ,不妨设 \(s_{i}<s_{j}\) ,如果 \(s_{i}<a_{j}\) ,显然是要 \(i\) 先去试试,如果 \(s_{i}>a_{j}\) ,先让 \(i\) 上,对 \(j\) 显然没有影响。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5 + 5;
int ans, d, nn, n;
struct node
{
int s, a;
}a[N];
bool cmp(node a, node b)
{
if(max(a.a, a.s) == max(b.a, b.s))
{
return a.s < b.s;
}
return max(a.a, a.s) < max(b.a, b.s);
}
signed main()
{
cin >> n >> d;
for(int i = 1; i <= n; i ++) cin >> a[i].s >> a[i].a;
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i ++)
{
if(a[i].s >= d)
{
ans ++;
d = max(d, a[i].a);
// cout << "qwq: "<< a[i].s << " " << a[i].a << endl;
}
}
cout << ans << endl;
}
AT_arc121_d [ARC121D] 1 or 2
思路
当只能吃两颗糖时,用最小的匹配最大的、次小的匹配次大的、第三小的匹配第三大的……一定是最优的。
原理小学生都会,这里就不证明了。
那么考虑只能吃一颗的情况。
考虑在糖果中加入美味度为 \(0\) 的糖果,那么就可以像只吃两颗糖一样匹配了。
代码要点:
- 美味度为 \(0\) 的糖果需要加入序列中并重新排序(因为会有负数的糖果qwq)。
- 可能糖果总数不是偶数,那么会出现没有匹配上的糖果,需要单独处理。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 1e18;
const int N = 5e5 + 5;
int n, a[N], minn, maxx, ans = inf;
signed main()
{
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = n % 2; i <= n; i += 2)
{
sort(a + 1, a + n + 1);
minn = inf, maxx = -inf;
int l = 1, r = n;
while(l < r)
{
// cout <<"qwq: "<< l << " " << r << " " << a[l]<< " " << a[r] << endl;
minn = min(minn, a[l] + a[r]);
maxx = max(maxx, a[l] + a[r]);
// cout << minn << " " << maxx << endl;
l ++, r --;
}
if(l == r)
{
minn = min(minn, a[r]);
maxx = max(maxx, a[r]);
}
ans = min(ans, maxx - minn);
n ++;
a[n]= 0;
}
cout << ans << endl;
}
P8162 [JOI 2022 Final] 让我们赢得选举 / Let's Win the Election
思路
显然,对于每个州,演讲时间只有 \(0\),\(a_{i}\),\(b_{i}\) 三种情况。
定义演讲时间为 \(a_{i}\) 的州为 \(\operatorname{A}\) 类州(即只获得选票),演讲时间为 \(b_{i}\) 的州为 \(\operatorname{B}\) 类州(即获得协作者),演讲时间为 \(0\) 的州为 \(\operatorname{C}\) 类州(即不去演讲)。
先去演讲 \(\operatorname{B}\) 类州,再去演讲 \(\operatorname{A}\) 类州是更优的。
所以我们按照 \(b_{i}\) 排序。
我们枚举 \(b_{i}\) ,进行 \(\operatorname{dp}\)。
由于是按照 \(b_{i}\) 升序排列的,那么如果 \(\operatorname{B}\) 类州之前存在 \(\operatorname{C}\) 类州,让该C类州成为 \(\operatorname{B}\) 类州,该 \(\operatorname{B}\) 类州成为 \(\operatorname{C}\) 类州是更优的。
那么序列的前半部分只有 \(\operatorname{A}\) 类州或 \(\operatorname{B}\) 类州,后半部分只有 \(\operatorname{A}\) 类州或 \(\operatorname{C}\) 类州。
所以定义 \(dp_{i,j}\) 表示枚举到第 \(i\) 个州,选了 \(j\) 个 \(\operatorname{B}\) 类州的最少时间。
枚举 \(\operatorname{B}\) 类州的个数 \(\operatorname{sum}\),然后进行 \(\operatorname{dp}\)。
\(\operatorname{dp}\) 到 \(\operatorname{sum}\) 后停止,计算剩下的州中最小的 \(\operatorname{A}\) 类州的时间。
设后 \(x\) 个州里,\(a_{i}\) 最小的 \(y\) 个州的 \(a_{i}\) 之和为 \(w(x,y)\)。
那么答案就是 \(\min_{i = sum}^{k}dp_{i,sum} + w(n - i,k - i)\)。
\(\operatorname{dp}\) 的时间复杂度是 \(O(n^{2})\),由于要枚举 \(\operatorname{B}\) 类州的个数,所以总时间复杂度 \(O(n^{3})\)。
点击查看代码
#include<bits/stdc++.h>
#define ldb double
using namespace std;
const int inf = 1e9;
const int N = 505;
struct node
{
int a, b;
}a[N], aa[N];
bool cmp(node a, node b)
{
return a.b < b.b;
}
bool cmp1(node a, node b)
{
return a.a < b.a;
}
int n, k;
ldb dp[N][N], f[N][N], ans = inf;
signed main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++)
{
cin >> a[i].a >> a[i].b;
if(a[i].b == -1) a[i].b = inf;
aa[i].a = a[i].a, aa[i].b = a[i].b;
}
sort(aa + 1, aa + n + 1, cmp);
sort(a + 1, a + n + 1, cmp);
for(int i = n; i >= 1; i --)//预处理
{
sort(aa + i, aa + n + 1, cmp1);
for(int j = i; j <= n; j ++) f[i][j - i + 1] = f[i][j - i] + aa[j].a;
}
for(int i = 0; i < k; i ++)//枚举找几个人
{
for (int l = 0; l <= k; l++) for (int j = 0; j <= i; j++) dp[l][j] = inf;
dp[0][0] = 0;
for(int j = 1; j <= k; j ++)
{
dp[j][0] = dp[j - 1][0] + a[j].a * 1.0 / (i + 1);
for(int l = 1; l <= i; l ++)
{
dp[j][l] = min(dp[j - 1][l - 1] + a[j].b * 1.0 / l, dp[j - 1][l] + a[j].a * 1.0 / (i + 1));
}
}
for(int j = 0; j <= k; j ++)
{
ans = min(ans, dp[j][i] + f[j + 1][k - j] * 1.0 / (i + 1));
}
}
printf("%.5lf", ans);
}

浙公网安备 33010602011771号