codeforces1914 C~F

C - Quests

要解释第 i 个任务,前面的任务必须全部解锁。解锁后,剩余的次数可以重复做前面的任务。

先记录解锁到第 i 个任务的总经验值,记录前 i 个任务的最大值。

解锁到第 i 个,让剩余次数乘前面任务中b最大的。

如果 k > n k>n k>n 再算 m a x ( s u m , s a [ i ] + t ∗ m b [ i ] ) max(sum, sa[i] + t*mb[i]) max(sum,sa[i]+t∗mb[i]) 。

c++ 复制代码
#include<iostream>
#include<map>
#include<vector>
#include<string>
using namespace std;
void solve() {
	int n, k;
	cin >> n >> k;
	vector<int>a(n), b(n);
	vector<int>sa(n, 0), mb(n, 0);
	for (int i = 0; i < n; i++) cin >> a[i];

	for (int i = 0; i < n; i++)	cin >> b[i];

	sa[0] = a[0];
	for (int i = 1; i < n; i++)	sa[i] = sa[i - 1] + a[i];
	//前缀ai和

	mb[0] = b[0];
	for (int i = 1; i < n; i++)	mb[i] = max(b[i], mb[i - 1]);
	//前bi中最大的

	int sum = 0;
	for (int i = 0; i < min(n, k); i++) {
		int t = k - 1 - i;
		sum = max(sum, sa[i] + t*mb[i]);
	}
	if (k > n) {
		sum = max(sum, sa[n - 1] + mb[n - 1] * (k - n));
	}
	cout << sum << endl;


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

D - Three Activities

三个日子 x , y , z x,y,z x,y,z ,要 a [ x ] + b [ y ] + c [ z ] a[x]+b[y]+c[z] a[x]+b[y]+c[z] 最大。并且 x = = y ∣ ∣ x = = z ∣ ∣ y = = z x==y||x==z||y==z x==y∣∣x==z∣∣y==z 这样的日子是不行的。

先找出每个数组前三个最大的,记录元素的值和下标。再枚举所有组合 3 ∗ 3 = 27 3*3=27 3∗3=27 种。找最大值

c++ 复制代码
#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#include <functional>
using namespace std;
typedef long long ll;
bool cmp(pair<int, int>a, pair<int, int>b) {
	return a.first > b.first;
}
void solve() {
	int n;
	cin >> n;
	vector<pair<int, int>>a, b, c;
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		a.push_back({x, i});
	}
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		b.push_back({x, i});
	}
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		c.push_back({x, i});
	}
	sort(a.begin(),a.end(),cmp);
	sort(b.begin(),b.end(),cmp);
	sort(c.begin(),c.end(),cmp);
	
	ll mx=0;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			for (int k = 0; k < 3; k++) {
				if(a[i].second==b[j].second||a[i].second==c[k].second||b[j].second==c[k].second) continue;
				mx=max((ll)(a[i].first+b[j].first+c[k].first),mx);
			}
		}
	}
	cout<<mx<<endl;
}
int main() {
	int T;
	cin >> T;
	while (T--) {
		solve();
	}
}

E - Game with Marbles (Easy )

两人轮流选,爱丽丝要最大化得分,鲍勃要最小化得分。用dp数组存每个状态的最优贡献。

mask 二进制位为1表示被选,0:未选的。

d p [ m a s k ] dp[mask] dp[mask] 表示选 mask 时,双方的最优策略。最终答案是 d p [ 0 ] dp[0] dp[0]

_ _ b u i l t i n _ p o p c o u n t ( m a s k ) \\ builtin\_popcount(mask) __builtin_popcount(mask) 统计 mask 中二进制1的个数。为偶数时爱丽丝选,奇数鲍勃选。


dp+逆序遍历+位掩码

为什么逆序遍历?

计算 d p [ m a s k ] dp[mask] dp[mask] 时,需要依赖 "选了一个新颜色后的状态" t 的 d p [ t ] dp[t] dp[t] 的值。

当 k = = n k == n k==n 时, m a s k = ( 1 < < n ) − 1 mask = (1<<n)-1 mask=(1<<n)−1(二进制全 1),没有可再选的颜色,游戏结束,贡献为 0。

m a s k & ( 1 < < j ) mask \& (1 << j) mask&(1<<j) 判断整数mask的第 j 个二进制位是否为1,看该颜色是否被选。非0->颜色已选 就跳过

m a s k ∣ ( 1 < < j ) mask | (1 << j) mask∣(1<<j) 选择颜色 j 将整数mask第 j 个二进制位设置为1其他位不变,来更新状态。实现状态转移


c++ 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve() {
	int n;
	cin >> n;
	vector<ll>a(n), b(n);
	for (int i = 0; i < n; i++) cin >> a[i];
	for (int i = 0; i < n; i++) cin >> b[i];
	vector<ll>dp(1 << n, 0);
	for (int mask = (1 << n) - 2; mask >= 0; mask--) {
		int k = __builtin_popcount(mask);
		if (k % 2 == 0) {//爱丽丝
			dp[mask] = -1e18;
			for (int j = 0; j < n; j++) {
				if (mask & (1 << j)) continue;
				int t = mask | (1 << j);
				dp[mask] = max(dp[mask], a[j] - 1 + dp[t]);
			}
		} else {//鲍勃
			dp[mask] = 1e18;
			for (int j = 0; j < n; j++) {
				if (mask & (1 << j)) continue;
				int t = mask | (1 << j);
				dp[mask] = min(dp[mask], 1 - b[j] + dp[t]);
			}
		}
	}
	cout << dp[0] << endl;

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

F - Game with Marbles (Hard )

方法二:贪心

对于选择问题,谁先选哪个元素会影响总得分。

假设只有两种元素, x = ( a 1 , a 2 ) x=(a_1,a_2) x=(a1,a2) y = ( b 1 , b 2 ) y=(b_1,b_2) y=(b1,b2) ,爱丽丝先选有两种情况:

  • 爱丽丝选 x ,鲍勃选 y : ( a 1 − 1 ) + ( 1 − b 2 ) = a 1 − b 2 (a_1-1)+(1-b_2)=a_1-b_2 (a1−1)+(1−b2)=a1−b2
  • 爱丽丝选 y , 鲍勃选 x : ( a 2 − 1 ) + ( 1 − b 1 ) = a 2 − b 1 (a_2-1)+(1-b_1)=a_2-b_1 (a2−1)+(1−b1)=a2−b1

( a 1 − b 2 ) − ( a 2 − b 1 ) = ( a 1 + b 1 ) − ( a 2 + b 2 ) (a_1-b_2)-(a_2-b_1)=(a1 + b1) - (a2 + b2) (a1−b2)−(a2−b1)=(a1+b1)−(a2+b2)

如果a1 + b1 > a2 + b2:第一种顺序(先 x 后 y)总贡献更大,对爱丽丝更有利;

反之,第二种顺序更好。

所以对 a [ i ] + b [ i ] a[i]+b[i] a[i]+b[i] 排序,然后两人轮流选择。

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool cmp(pair<ll, ll>x, pair<ll, ll>y) {
	return x.first + x.second > y.first + y.second;
}
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		vector<ll> a(n), b(n);
		for (int i = 0; i < n; i++) cin >> a[i];
		for (int i = 0; i < n; i++) cin >> b[i];

		ll sum = 0;
		vector<pair<ll, ll>>c;
		for (int i = 0; i < n; i++) {
			c.push_back({a[i], b[i]});
		}
		sort(c.begin(), c.end(), cmp);
		for (int i = 0; i < n; i++) {
			if (i % 2==0) {
				sum += c[i].first - 1;
			} else sum += 1 - c[i].second;
		}
		cout << sum << '\n';
	}
	return 0;
}
相关推荐
wyiyiyi2 小时前
【数据结构+算法】进栈顺序推算、卡特兰数与逆波兰表达式
汇编·数据结构·笔记·算法
天若有情6732 小时前
Multi-Stride Predictive RNG:革命性的可控随机数生成算法
算法·算法设计·c++编程·随机数生成·msp-rng·魔术算法
C_Liu_2 小时前
14:C++:二叉搜索树
算法
white-persist2 小时前
汇编代码详细解释:汇编语言如何转化为对应的C语言,怎么转化为对应的C代码?
java·c语言·前端·网络·汇编·安全·网络安全
CC-NX2 小时前
32位汇编:实验9分支程序结构使用
汇编·算法·win32·分支结构
万岳科技系统开发2 小时前
外卖小程序中的高并发处理:如何应对大流量订单的挑战
算法·小程序·开源
TL滕2 小时前
从0开始学算法——第二天(时间、空间复杂度)
数据结构·笔记·学习·算法
满天星83035773 小时前
【C++】智能指针
c语言·开发语言·c++·visual studio
旺仔老馒头.4 小时前
【数据结构与算法】手撕排序算法(二)
c语言·数据结构·算法·排序算法