Codeforces Round #592 (Div. 2)

题目链接

这场感觉难度 C > E > D > B > A,当时放弃了C写D,D有个数组开小了,在本地一直过不了样例,找了一个多小时bug,最后两题自闭。

A. Pens and Pencils

向上取整就ok了。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int a[N],b[N];
int main()
{
    int T;
    cin>>T;
    while(T--){
    	int a, b, c, d, k;
    	cin>>a>>b>>c>>d>>k;
    	int t = a / c + (a % c != 0) + b / d + (b % d != 0);
    	if(t > k) puts("-1");
    	else printf("%d %d\n", a / c + (a % c != 0), b / d + (b % d != 0));
	} 
}

 

B. Rooms and Staircases

题意:有一栋两层楼的房子,在同一楼可以随意移动,两楼之间有楼梯,可以上下楼。你可以选择任意一个房间为起始点,不能多次访问同一房间,问最多可以走多少个房间。

题解:首先可以肯定的是起始点选择在左端点或者右端点,然后找一个离起始点最远的楼梯上楼,再走到左端点或者右端点。这四种情况取个max就是答案了。比赛时代码写的有点复杂了。

#include<bits/stdc++.h>
using namespace std;
const int N = 1100;
char s[N];
int main()
{
	int T, n;
	cin>>T;
	while(T--){
		cin>>n>>s + 1;
		int ans = n;
		for(int i = 1; i <= n; ++i){
			int tmp = 0;
			if(s[i] == '1')
				tmp = max(2 * i, i + n - i + 1);
			ans = max(ans, tmp);
		}
		for(int i = n; i >= 1; --i){
			int tmp = 0;
			if(s[i] == '1'){
				int t = n - i + 1;
				tmp = max(2 * t, t + i);
			}
			ans = max(ans, tmp);
		}
		printf("%d\n", ans);
	}
}

 

C. The Football Season

题意:一支球队在一个赛季有n场足球赛,每场足球赛有三种结果。赢:得w分;平局:得d分;输:不得分。已知最后这支球队得了p分,但是不知道这支球队胜负平的情况,让你求一组可行解。

题解:暴力即可。枚举平局场数,可以将平局局数限制在 w - 1。因为对于同样的分数 w * d,可以赢d场,可以平w场,但是题目保证d严格小于w,所以赢d场肯定最优。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	ll n, p, d, w;
	cin>>n>>p>>w>>d;
	for(ll i = 0; i <= n && i <= 100000; ++i){
		ll tmp = p - i * d;
		if(tmp >= 0 && tmp % w == 0){
			ll t = tmp / w;
			if(t + i <= n){
				printf("%lld %lld %lld\n", t, i, n - t - i);
				return 0;
			}
		}
	} 
	puts("-1");
}

 

D. Paint the Tree

题意:给一颗树,让你给结点染色。有三种颜色,每个结点染不同的颜色有不同的花费。染色规则是,对于相邻的三个结点不能有相同的颜色。

题解:首先可以判断如果一个结点和三个或以上的点相邻是肯定不能染色的。判断完非法情况之后,找一个出度为1的点作为起始点,给这个点和它儿子进行染色,然后再dfs给后面的点染色,求一个最小值的组合就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
vector<int>e[N];
ll a[4][N]; 
int col[N], t[N];
//pc是爷爷的颜色,fc是父亲的颜色 
ll dfs(int pc, int fc, int fa, int u){
	ll ans = 1e18;
	
	for(auto v : e[u]){
		if(v == fa) continue;
		t[u] = 6 - pc - fc; //染色 
		ans = a[t[u]][u] + dfs(fc, t[u], u, v);
	}

	if(e[u].size() == 1){//叶子结点 
		t[u] = 6 - pc - fc;//染色 
		ans = a[t[u]][u];
	}
	
	return ans;
}

int main()
{
	int n, flag = 0;
	scanf("%d", &n);
	for(int i = 1; i <= 3; ++i)
	for(int j = 1; j <= n; ++j)
	scanf("%lld", &a[i][j]);
	for(int i = 1; i < n; ++i){
		int u, v;
		scanf("%d%d", &u, &v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	
	int s1, s2, s3; //祖宗,父亲,儿子结点 
	for(int i = 1; i <= n; ++i){
		if(e[i].size() >= 3) flag = 1;
		if(e[i].size() == 1) s1 = i; 
	}
	if(flag) return puts("-1");
	
	s2 = e[s1][0];
	for(auto v : e[s2]) 
	if(s1 != v) s3 = v;

	ll ans = 1e18;
	for(int i = 1; i <= 3; ++i){
		for(int j = 1; j <= 3; ++j){
			if(i == j) continue;
			ll tmp = a[i][s1] + a[j][s2] + dfs(i, j, s2, s3);
			t[s1] = i; t[s2] = j;
			if(ans > tmp){
				ans = tmp;
				for(int k = 1; k <= n; ++k)//保存路径 
					col[k] = t[k];
			}
		}
	}
	
	printf("%lld\n", ans);
	for(int i = 1; i <= n; ++i) 
		printf("%d ", col[i]);
}

 

E. Minimizing Difference

题意:n个数,有两种操作:将一个数加1,将一个数减1。最多可以操做k次,让你使得此时数列最大值减最小值最小。

题解:贪心就完事了,先排个序,然后不断让最大值和最小值向中间逼近。逼近的优先级是,两端点的个数大小,个数少的优先逼近。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a[N];
int main()
{
	ll n, k;
	cin >> n >> k;
	for(int i = 1; i <= n; ++i)
		scanf("%d", &a[i]);
	sort(a + 1, a + 1 + n);
	int l = 1, r = n;
	ll cl = 1, cr = 1;//最大值最小值个数 
	int mn = a[1], mx = a[n];
	while(l < r){
		if(cl <= cr){//根据个数优先级选择哪个端点逼近 
			ll tmp = (a[l + 1] - a[l]) * cl;
			if(k >= tmp){
				k -= tmp;
				l++;
				cl++;
				mn = a[l];
			}
			else {
				mn = mn + k / cl;
				k = 0; 
			}
		}
		else {
			ll tmp = (a[r] - a[r - 1]) * cr;
			if(k >= tmp){
				k -= tmp;
				r--;
				cr++;
				mx = a[r];
			}
			else {
				mx = mx + k / cr;
				k = 0;
			}
		}
		if(!k) break;
	}
	printf("%lld\n", mx - mn);
 } 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值