【Codeforces】Educational Codeforces Round 120 (Rated for Div. 2)

在这里插入图片描述
题意:给定三条边。问:能否通过只拆解一条边构成两两相同的四条边?
思路:分为两种情况。
   case1:两条边之和等于第三边时;
   case2:两条边相同且第三条边为偶数。
   为了方便比较可以先进行排序。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;

void solve()
{
	vector<ll>v(3);
	for(int i=0;i<3;i++){
		cin>>v[i];
	}
	sort(v.begin(),v.end());
	//分情况
	if(v[0]+v[1]==v[2]||(v[0]==v[1]&&v[2]%2==0)||(v[2]==v[1]&&v[0]%2==0)){
		cout<<"YES\n";
	} else {
		cout<<"NO\n";
	}
} 

int main()
{
	int t;
	cin>>t;
	while(t--) solve();
	return 0;
}

在这里插入图片描述
题意:给出一组排列,再给出一个字符串。排列中的每一个数字表示对一首歌的评分,字符串中的’0’表示不喜欢对应下标的歌曲,'1’表示喜欢对应下标的歌曲。要求对歌曲重新打分,所有喜欢歌曲的评分要高于不喜欢的歌曲且∑|重打分数−原分数| 最小。

思路:串中为1的歌曲(喜欢的歌曲)的打分必须要大于不喜欢的,并且要满足∑|重打分数−原分数| 最小则必须原来打分高的现在打分也要相对高。可以确立两种优先级1,喜欢不喜欢 2,原打分相对高低。
依照优先级排序并赋值即可,由于赋值要赋值到原位置,所以要保存原次序。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;

struct node {
	int data, noi, flag;
	//flag喜欢
	//noi原顺序
};

void solve()
{
	int n;
	string s;
	cin >> n;
	vector<node>v(n + 1);
	vector<int>b(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> v[i].data;
		v[i].noi = i;
	}
	cin >> s;
	for (int i = 0; s[i]; i++) {
		if (s[i] == '1') v[i + 1].flag = 1;//标记是否喜欢
	}
	sort(v.begin() + 1, v.end(), [](const node& t1, const node& t2) {
		if (t1.flag != t2.flag)
			return t1.flag < t2.flag;
		else
			return t1.data < t2.data;
		});
	//按优先级向原位置赋值
	for (int i = n; i >= 1; i--) {
		b[v[i].noi] = i;
	}
	for (int i = 1; i <= n; i++) {
		cout << b[i] << ' ';
	}
	cout << endl;
}

int main()
{
	int t;
	cin >> t;
	while (t--) solve();
	return 0;
}

在这里插入图片描述
题意:给出序列长度n,以及限定值k。
   允许两种操作:
   op1:任选两个数字将两个数字变为相同的(变为两个中的任一均可)。
   op2:任选数字自减。
问:至少多少次操作可以使序列元素之和不大于k。

思路:注意最优解是op1和op2的组合求出的,根据贪心思想op1一定是对最小值操作,op2一定是对较大值和最小值操作且变为最小值。
   那么,令k = sum-kk赋值为要想满足题意原序列需要减去的值。设x表示x个较大元素执行了op2,设y为最小值需要需要减去的部分(即最小值执行了y次op1),s[x]为前x个元素前缀和。
则存在如下关系时满足题意,即消耗部分大于等于需要消耗部分。

k <= y + s[x] - x*(a[n]-y)

等价变换后可得到y的表达式,注意y必须向上取整。由于x是有取值范围的(最多将非最小值的所有值变为最小值即n-1步),所以最后的解是可枚举求出的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;

void solve()
{
	ll n,k,sum=0;
	cin>>n>>k;
	vector<ll>a(n+1),s(n+1,0); 
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i]; //总和 
	}
	if(k>=sum) {
		cout<<0<<endl;
		return;
	}
	sort(a.begin()+1,a.end(),greater<ll>());
	for(int i=1;i<=n;i++){
		s[i]=s[i-1]+a[i];
	}
	k = sum-k;//要想满足题意原序列需要减去的值
	//推公式 设x为使x个最大元素变为a[n] 设y为最小值需要需要减去的部分 
	//k <= y + s[x] - x*(a[n]-y)
	ll ans = k;
	for(int x=1;x<=n-1;x++){
		ll y = max(0ll,(k-s[x]+x*a[n]+x)/(x+1));
		ans = min(ans,x+y);
	}
	cout<<ans<<endl;
} 

int main()
{
	int t;
	cin>>t;
	while(t--) solve();
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sophon、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值