比赛链接:Codeforces Round #823 (Div. 2)
A: 贪心![](https://i-blog.csdnimg.cn/blog_migrate/659c577bc3f85e49b9e2e6274ba314c2.png)
题意:给定一个长度为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:二分![](https://i-blog.csdnimg.cn/blog_migrate/17ba62a7869b4020cfc326448c498b53.png)
题意:有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:思维+贪心![](https://i-blog.csdnimg.cn/blog_migrate/8365049188a40b2692b786140468015d.png)
题意:给定一种操作方法求问在对字符串 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();
}