Codeforces Round #823 (Div. 2)

 比赛链接:Codeforces Round #823 (Div. 2)

A: 贪心

题意:给定一个长度为N的数组。第一个操作为:消除一个位置的元素,代价为1.第二个操作为:消除相同元素,代价为c。可以执行两个操作无限次。问怎样花费最小的代价,能够消除完所有元素

分析:怎样每步操作取得最优?如果一个元素出现了m次,那么操作1的代价就为m,操作2的代价为c,这时候的代价最小为:min(m,c)。依次进行贪心操作,最终取得最优解。

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int cnt[N];

inline void solve(){
	memset(cnt,0,sizeof cnt);
	int n,c;cin>>n>>c;
	for(int i=1;i<=n;i++){
		int x;cin>>x;
		cnt[x]++;
	}
	int ans=0;
	for(int i=1;i<=100;i++){
		if(cnt[i]>c) ans+=c;
		else ans+=cnt[i];
	}
	cout<<ans<<"\n";
}

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

 B:二分

题意:有n个人要到一个地方集合,每人要从a[i]出发,出发前要打扮t[i]分钟,走一单位的距离要花费1时间,求最合适的集合的位置。

思路:浮点二分。二分位置即可,算出每个人能够到达的范围,进行区间求交集。满足二分的条件一定是交集不为空。最后二分出来的一定是一个点(满足绝对误差范围)

这里有道类似的题: 二分经典例题_Black_Chocolate.的博客-CSDN博客

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int n,m;
int x[N],t[N];
double ans;
bool check(double mid){
	double l=-2e18,r=2e18;//定义区间无穷大
	for(int i=1;i<=n;i++){//枚举每个人所能达到的范围
		if(mid<t[i])return false;
		else{
			l=max(l,x[i]+t[i]-mid);//左区间求交集
			r=min(r,x[i]+mid-t[i]);//右区间求交集
		}
	}
	ans=l;
	if(r>=l-1e-8) return true;//满足绝对误差范围
	return false;
}
void solve(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>x[i];
	for(int i=1;i<=n;i++)cin>>t[i];
	double l=0,r=2e18;
  	for(int i=1;i<=100;i++){
    	double mid=(l+r)/2;
    	if(check(mid))r=mid;
    	else l=mid;
    }
  	printf("%.10lf\n",fabs(ans));
}
signed main(){
		int T;cin>>T;
		while(T--) solve();	
}

 C:思维+贪心

题意:给定一种操作方法求问在对字符串 s 进行任意次操作后,字符串 s 的字典序最小串 

分析:通过样例发现 ,我们要操作的数具有以下性质:

这个数一定是逆序的。意思就是,这个数的后面一定有比它小的数。

ps:这个不容易解释的通,大家分析几组样例就可以发现这个性质。

代码:

#include<bits/stdc++.h>
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N=2e5+10;
int p[N];//用于判断i位置上的数是否为逆序

inline void solve(){
	string s;cin>>s;int n=s.size();
	for(int i=1;i<=n;i++) p[i]=0;
	s="*"+s;int res=2e9+10;
	for(int i=n;i>=1;i--){//用于标记p//挺巧的方法O(N)
		int x=s[i]-'0';
		if(x>res) p[i]=1;
		else res=x;
	}
	string ans;//用ans记录答案
	for(int i=n;i>=1;i--){//存操作后的数
		if(p[i]){//该位置上的数是逆序
			if(s[i]-'0'<9) ans+=char(s[i]+1);
			else ans+=s[i];
		}
		else ans+=s[i];
	}
	sort(ans.begin(),ans.end());//排序
	cout<<ans<<"\n";
}

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值