第五次训练赛 (思维,贪心,最长公共子序列)

A题

思路:q/x是向上取整,我们要找所有和最大值和最小值,只需要利用这个取整产生的误差,每个数都除以x向上取整即为最大,所有数之和除以x向上取整即为最小。
向上取整:(a + b - 1) / b 为a/b向上取整
(a + b / 2) / 2 为a / b 四舍五入取整

#include<cstdio>
#include<iostream>
#include<string>
#include<stack>
using namespace std;
typedef long long ll;
int t;
ll a[1000000], x, n;
void work()
{
    
    
	cin >> n >> x;
	ll max1 = 0, min1 = 0, sum = 0;
	for(int i = 1; i <=n ; ++i) 
	{
    
    
		scanf("%lld", &a[i]);
		sum += a[i];
		max1 += (a[i] + x - 1) / x;
	}
	min1 = (sum + x - 1) / x;
	cout << min1 << " " << max1 << endl;
	
}
int main()
{
    
    
	ios::sync_with_stdio(false);
    cin >> t;
    while(t--) work();
    return 0;
}

B题

题意:给你一个数组和x,你的初始分数为0。从头开始遍历数组,对于当前的元素,不能整除x时就结束,输出分数;可以整除x就将分数增加当前数字大小,并且在数组末尾添加x个大小为a[i]除以x的元素。

如果按照题意来模拟数组肯定会爆掉…其实我们不需要不断更新数组a,我们可以用一个数组b来记录当前大小为a[i]的元素有b[i]个。这样如果a[i]能整除 x的话就更新a[i]为a[i]/x,b[i]=b[i]*x。
这里要注意初始的分数其实是给你的数组元素和,b[i]初始为1,初始化完成之后才会进入真正的操作~

#include <bits/stdc++.h>
using namespace std;
#define qc std::ios::sync_with_stdio(0);
int a[100001];
int b[100001];

int main() {
    
    
	qc;
	cin.tie(0);
	int t;
	cin >> t;
	while (t--) {
    
    
		int n, k;
		long long ans = 0;
		cin >> n >> k;
		for (int i = 0; i < n; i++) {
    
    
			cin >> a[i];
			b[i] = 1;
			ans += a[i];
		}
		int flag = 0;
		while (1) {
    
    
			for (int i = 0; i < n; i++) {
    
    
				if (a[i] % k != 0) {
    
    
					flag = 1;
					break;
				} else {
    
    
					a[i] = a[i] / k;
					b[i] = b[i] * k;
					ans += b[i] * a[i];
				}
			}
			if (flag == 1)
				break;
		}
		cout << ans << endl;
	}
}

C题
题意:
n个人,m件礼物,每件礼物对应价值c[i](递增给出),每个人对应一个编号a[i],你可以送编号<=a[i]的礼物,也可以直接送c[a[i]]的现金,求怎么送礼物使得花费最小

思路:礼物是唯一的,贪心分配礼物,把最便宜的礼物分配给编号最高的人

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 10;
int n, m;
int a[N], c[N];
int main() {
    
    
	int t; cin >> t;
	while (t--) {
    
    
		cin >> n >> m;
		for (int i = 1; i <= n; ++i)cin >> a[i];
		for (int i = 1; i <= m; ++i)cin >> c[i];
		sort(a + 1, a + 1 + n, greater<int>());
		ll res = 0;
		for (int i = 1, j = 1; i <= n; ++i) {
    
    
			if (a[i] > j) {
    
    
				res += c[j];
				++j;
			}
			else res += c[a[i]];
		}
		cout << res << endl;
	}
	return 0;
}

H题
题意:给定r序列和b序列,现在在不改动r序列和b序列内部顺序的前提下,将r和b序列凑成a序列,使得a序列的最大前缀和最大。求解该值。

题解:分别求解r序列和b序列的最大前缀和,相加即可。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int t;
ll a[1000], x, n, m, b[1000];
void work()
{
    
    
	memset(a, 0, sizeof(a));
	cin >> n;
	ll max1 = 0, max2 = 0;
	for(int i = 1; i <= n; ++i)
	{
    
    
		scanf("%lld", &a[i]);
		a[i] += a[i-1];
		max1 = max(max1, a[i]);
	}
	cin >> m;
	for(int i = n+2; i <= n+m+1; ++i)
	{
    
    
		scanf("%lld", &a[i]);
		a[i] += a[i-1];
		max2 = max(max2, a[i]);
	}
	cout << max1 + max2 << endl;
}
int main()
{
    
    
	ios::sync_with_stdio(false);
    cin >> t;
    while(t--) work();
    return 0;
}

G题
poj 1458

猜你喜欢

转载自blog.csdn.net/cosx_/article/details/113401964