Codeforces #510 1042 div2 ABC

这次比#509多考了800分左右结果反而掉rating了,据说是这次参加人数少。纠结ing >_<

A. Benches

给定n个正整数,现在要把数字m拆一拆分配到这n个正整数的某些上面,设k为分配后这n个数最大的一个,求k可能的最小值与最大值

先求出目前最大的数maxa,k一定是maxa加上一些分配到的数,首先明确的是k一定大于等于maxa,不可能小于,那么先把其他数字分的和maxa一样大,然后剩下的数rem平均分配,注意求的是最大的,平均分配时,除法会向下取整,但是如果不是整除,余数也要平均分配,最终就是( rem/m ) + 1

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 200000 + 10;
int n,m,a[MAXN],tot,vis[MAXN],maxa,sum,kmin,ave;
int main() {
	scanf("%d%d", &n, &m);
	for(int i=1; i<=n; i++) {
		scanf("%d", &a[i]);
		maxa = max(maxa, a[i]);
	}
	for(int i=1; i<=n; i++) {
		sum += maxa - a[i];
	}
	if(sum >= m) {
		kmin = maxa;
	} else {
		int rem = m - sum;
		if(rem % n == 0) ave = rem / n;
		else ave = rem / n + 1;
		kmin = maxa + ave;
	}
	printf("%d %d", kmin, maxa + m);
    return 0;
}

B. Vitamins

输入一对参数表示一瓶果汁,第一个是花费,第二个是所含维生素(字符串),字符串保证只存在ABC三种字符并且ABC各最多出现一次,如果要喝一些果汁,使喝的这些果汁所含维生素构成的集合是ABC,求最小花费

貌似挺难搞的,但是想到,果汁的维生素过于简单,简单到可以手算。。。而且基于贪心的原则,都只含A维生素的果汁显然只需要保留花费小的那个来寻找答案,若将果汁按维生素分类,其实类别固定而且很少,然后可以强行打出所有可能的判断,每次取最小,把每种可能都试一下就行了。。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 200000 + 10;
const int inf = 1<<30;
long long n,m,tot,vis[MAXN],a=inf,b=inf,c=inf,ab=inf,bc=inf,ac=inf,abc=inf,ans=inf;
int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; i++) {
		long long cost;
		string juice;
		cin >> cost >> juice;
		if(juice == "A") {
			a = min(a, cost);
		} else if(juice == "B") {
			b = min(b, cost);
		} else if(juice == "C") {
			c = min(c, cost);
		} else if(juice == "AB" || juice == "BA") {
			ab = min(ab, cost);
		} else if(juice == "BC" || juice == "CB") {
			bc = min(bc, cost);
		} else if(juice == "AC" || juice == "CA") {
			ac = min(ac, cost);
		} else if(juice == "ABC" || juice == "ACB" || juice == "BAC") {
			abc = min(abc, cost);
		} else if(juice == "BCA" || juice == "CAB" || juice == "CBA") {
			abc = min(abc, cost);
		}
	}
	ans = min(ans, a + b + c);
	ans = min(ans, a + bc);
	ans = min(ans, b + ac);
	ans = min(ans, c + ab);
	ans = min(ans, ab + bc);
	ans = min(ans, ac + bc);
	ans = min(ans, ab + ac);
	ans = min(ans, abc);
	if(ans == inf) printf("-1");
	else printf("%I64d", ans);
    return 0;
}

C. Array Product

给你一个序列 a 1 a_1 a1~ a n a_n an,有两种操作
1.若i, j都在1到n范围内,用ai*aj代替ai同时删除aj
2.直接删掉一个数,但是这个操作只能做一次
虽然删除了,但是每个数在序列中的位置是不变的,这里的删除只是“不可用”的意思
然后进行n-1次上述操作,最后一定会剩下一个数,求使这个数最大的任意方案
注意ai范围在 − 1 e 9 - 1e9 1e9 ~ 1 e 9 1e9 1e9之间

这题样例真的良心。。。我一开始负数都没想到orz
使答案变小的ai可能为0或者负数,但是负负得正反而会更大。。。若有奇数个负数取其中最大的,然后把这个负数和一个0相乘就好了,对了,所有的0都可以“缩”成一个0,用这个0消去多余负数的影响,最后再把这个0删掉就好了(我一开始想的是先考虑把0删掉,如果有多余的负数就删那个负数,然而没想到可以用0消除那个负数orz)

但是有问题
1.如果数列中全是0,显然不能删掉了,
2.若负数个数为奇数,个数可以为1,但是如果为1,这个负数和0相乘之后,数列中又只剩下0了
总之删掉0的前提条件是数列中不能只剩下0
3.可以一个都不删除

事实上应该先想想数列有什么形态,全正全负全0还是有0有负什么的,别先急着做,往往容易忽略什么

样例正好提示你会有上述两种特殊情况,但是里面没有那种一个都不删除的情况。。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 200000 + 10;
const int INF = 1<<30;
struct arrays{
	int val, id, tag;
}arr[MAXN];
int n,m,numzero,numneg,vis[MAXN],zer[MAXN],pos=-1,a[MAXN];
int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; i++) {
		scanf("%d", &a[i]);		
		if(!a[i]) zer[++numzero] = i, vis[i] = 1;
		if(a[i] < 0) {
			numneg++;
			if(pos == -1 || a[i] > a[pos]) {
				pos = i;
			}
		}
	}
	if(numneg % 2)
		vis[pos] = 1;
	if(numzero == n || (numzero == n-1 && numneg == 1)) {
		for(int i=1; i<n; i++) {
			printf("1 %d %d\n", i, i+1);
		}
		return 0;
	}
	int pre = 0;
	for(int i=1; i<=n; i++) {
		if(vis[i]) {
			if(pre) {
				printf("1 %d %d\n", pre, i);
			}
			pre = i;
		}
	}
	if(pre)//还可以哪个都不用删
		printf("2 %d\n", pre);
	pre = 0;
	for(int i=1; i<=n; i++) {
		if(vis[i]) continue;
		if(pre) {
			printf("1 %d %d\n", pre, i);
		}
		pre = i;
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值