[每日随题2] 模拟 - 贪心 - 贪心

整体概述

  • 难度:1400 -> 1800 -> 2200

2028B.Alice's Adventures in Permuting

  • 标签:模拟

  • 前置知识:无

  • 难度:Div.2.B 1400

题目描述:

image

输入格式:

image

输出格式:

image

样例输入:

7
10 1 0
1 2 3
100 2 1
3 0 1
3 0 0
1000000000000000000 0 0
1000000000000000000 1000000000000000000 1000000000000000000

样例输出:

0
1
50
2
-1
-1
1000000000000000000

解题思路:

  • 注意到当 \(b\ne0\) 时,我们只需要知道在 \([0,n-1]\) 中出现了多少个数字,假设为 \(m\) 个数字,其余的数字都需要一步步地操作获得,所以答案就为 \(n-m\)

  • \(b=0\) 时。若 \(c\ge n\) 则答案为 \(n\);若 \(c=n-1\)\(c=n-2\) 则答案为 \(n-1\);否则无法最后形成一个排列(手动模拟一下 \(c\) 更小的情况),输出 \(-1\)

完整代码

#include<iostream>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 5e5+5;
inline void solve(){
	int n,b,c; cin >> n >> b >> c;
	if(b == 0){
		if(c >= n) cout << n << '\n';
		else if(c <= n-3) cout << -1 << '\n';
		else cout << n-1 << '\n';
	}else cout << (c>=n ? n : n-((n-1-c)/b+1)) << '\n';
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int T; cin >> T;
	while(T--) solve();
	return 0;
}

1990D.Grid Puzzle

  • 标签:贪心

  • 前置知识:无

  • 难度:Div.2.D 1800

题目描述:

image

输入格式:

image

输出格式:

image

样例输入:

10
1
0
4
2 4 4 2
4
3 2 1 0
3
0 3 0
3
0 1 3
3
3 1 0
4
3 1 0 3
4
0 2 2 2
6
1 3 4 2 0 4
8
2 2 5 2 3 4 2 4

样例输出:

0
3
2
1
2
2
3
2
4
6

解题思路:

  • 由于 n 很大,我们考虑每行之间的相互影响。

  • 我们不难发现,如果第 \(i\) 行的 \(a_i\) 很大,那必定会使用操作 \(2\)。手动画几个图可以发现,当 \(a_i \ge 5\) 时,这一行直接选择方案 \(2\) 即是最优(可以分类讨论证明)。

  • 那么我们按行来考虑,只有当第 \(i\) 行的 \(a_i\) 小于等于 \(4\) 的时候才会受到上一行的影响,那么我们只需要关注前面 \(4\) 个格子的颜色情况。

  • 我们可以记上一行的状态 \(last\)\(4\) 种,分别为 0:该行无黑格;1:前两格有黑格;2:后两格有黑格;3:前两格和后两格都有黑格

    \(last = 1\) 时,只填一个 \(2*2\) 在前两格
    \(last = 2\) 时,只填一个 \(2*2\) 在后两格
    \(last = 3\) 时,若 \(a_i\le2\) 则上一行用操作 \(2\),否则填两个 \(2*2\)

  • 从头到尾模拟一遍,最后注意一下最后一行的状态,\(last\ne 0\) 则再用一次操作 \(2\) 给最后一行即可。

完整代码

#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 2e5+5;
int a[N];
inline void solve(){
	int n; cin >> n;
	for(int i=1;i<=n;i++) cin >> a[i];
	int last = 0, res = 0;	// last 表示上一行状态, 0:无 1:前两个有 2:后两个 3:全有
	for(int i=1;i<=n;i++){
		if(a[i] >= 5 || a[i] == 0){
			res += (a[i] > 0) + (last > 0);
			last = 0;
		}else{
			if(last == 0){
				last = (a[i] <= 2 ? 1 : 3);
			}else if(last == 1){
				res += 1;
				last = a[i] <= 2 ? 0 : 2;
			}else if(last == 2){
				res += 1;
				last = 1;
			}else{
				if(a[i] <= 2) res += 1, last = 1;
				else res += 2, last = 0;
			}
		}
	}
	res += (last > 0);
	cout << res << '\n';
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int T; cin >> T;
	while(T--) solve();
	return 0;
}

1415E.New Game Plus!

  • 标签:贪心

  • 前置知识:STL-priority_queue

  • 难度:Technocup2021.ROUND2.E 2200

题目描述:

image

输入格式:

image

输出格式:

image

样例输入:

3 0
1 1 1
5 1
-1 -2 -3 -4 5
13 2
3 1 4 1 5 -9 -2 -6 -5 -3 -5 -8 -9

样例输出:

3
11
71

解题思路:

  • 注意到每次使用漏洞后,相当于重新启动了一局游戏。共 \(k+1\) 局游戏之间相互独立,那么我们考虑将 \(n\)\(BOSS\) 划分到 \(k+1\) 局游戏之中。

  • 我们不难发现,每局游戏中某个奖励为 \(a_i\)\(BOSS\) 被打败后,若本剧游戏后续还有 \(x\)\(BOSS\) 会被打败,则该 \(BOSS\) 带来的贡献为 \(x\times a_i\),所以 \(a_i\) 越大的 \(BOSS\) 需要越先打败。

  • 所以我们将 \(n\)\(BOSS\)\(a_i\) 从大到小排序,依次考虑每一个 \(BOSS\) 要被放入哪一局游戏。打败一个新的 \(BOSS\) 相当于选择一局游戏,获得其现有的分数。那么我们每次选择现有分数最大的那局游戏,打败该 \(BOSS\) 获取当前奖励,随后更新新的 \(BOSS\) 奖励。

  • 依次处理完所有 \(BOSS\) 即可,总复杂度 \(O(nlog_2^n)\)

完整代码

#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 5e5+5;
int a[N],n,k;
priority_queue<int,vector<int>,less<int>> qu;
inline void solve(){
	cin >> n >> k;
	for(int i=1;i<=n;i++) cin >> a[i];
	sort(a+1,a+1+n,[&](int x,int y){return x > y;});
	for(int i=1;i<=k+1;i++) qu.push(0);
	int res = 0;
	for(int i=1;i<=n;i++){
		int x = qu.top(); qu.pop();
		res += x;
		qu.push(x+a[i]);
	}
	cout << res;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int T; T = 1;
	while(T--) solve();
	return 0;
}

posted @ 2025-07-09 15:49  浅叶梦缘  阅读(9)  评论(0)    收藏  举报