文章目录
- 扫地机器人
 - 分糖果
 - 最小战斗力差距
 - 谈判
 - 纪念品分组
 
扫地机器人

 思路:
- 最优机器人清理方法:机器人清理方法先扫左边,有时间再扫右边。
 - 最短时间:通过枚举,从 1 开始,清理面积会越大直到全部面积的清理时间是最小时间。优化:二分枚举时间,由于随时间增大清理面积增大,单调可以用二分。
 
#include<iostream>
#include<stdbool.h>
using namespace std;
const int N = 1e5+10;
int a[N];
int n,k;
bool check(int mid){
    int pos=0;
    for(int i=1;i<=k;i++){
        int t=mid;
        t-=(a[i]-pos-1)*2;
        if(t<0)return false;
        pos = a[i]+t/2;
    }
    if(pos<n)return false;
    return true;
}
int main( ){
    cin>>n>>k;
    for(int i=1;i<=k;i++)cin>>a[k];
    sort(a+1,a+1+k);
    int l=1,r=2*n,ans=2*n;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    cout<<ans<<'\n';
    return 0;
}
 
分糖果

 思路:贪心中的规律题。先理解题意+找出规律。先排序,能保证最大的最小,然后分成三种情况,第一种全部字符相等,就平分,多余的放到最后一个。第二种,如果第 x 个和第一个相等就直接输出 x 到最后。第三种如果不相等,把 x 后面放到第一个,直接输出 x。x 肯定比第一个字符串大,并且 x 最小。
找规律的贪心,考验思维,将字符串分类讨论,设计贪心策略。
 先给字符串排序,然后我们可以分为三类讨论:
 1)字符串全相等(假设全a),那就是尽量使得每个人分到的字符串的最大长度尽可能小就行。
 2)s[x]==s[1],说明第x个是最小的字符带着后面所有的字符一起输出。
 3)s[x]!=s[1],后面一坨字符可以直接丢到s[1]后面,分给第一个同学。
#include<iostream>
using namespace std;
const int N =1e6+10;
char s[N];
int main( ){
    int n,x;cin>>n>>x;
    for(int i=1;i<=n;i++)cin>>s[i];
    sort(s+1,s+1+n);
    if(s[1]==s[n]){
        for(int i=1;i<=n/x+(n%x?1:0);i++)cout<<s[i];
    }else{
        if(s[1]==s[x])for(int i=x;i<=n;i++)cout<<s[i];
        else cout<<s[x];
    }
    return 0;
}
 
最小战斗力差距

 思路:贪心,所有方案中排序后划分分为 a,b 两个组会比不排序划分的战斗力更小。所以选择排序后将 a,b 划分,其中枚举所有结果选择最小的。
 要将战斗力分为两部分,为了使得差距最小,我们可以将战斗力排序后,找一个位置进行划分,使得左边的都在a,右边的都在b,从而这个差距就是这个位置两边的战斗力差距,说明差距的取值仅有n-1种,枚举即可。
 这个题启发我们,当混乱的数据不好处理,且排序不影响答案时,尝试先排序再分析。
#include<iostream>
using namespace std;
const int N = 1e5+10;
int a[N];
int main( ){
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+1+n);
    int ans=a[2]-a[1];
    for(int i=2;i<=n;i++)ans=min(ans,a[i]-a[i-1]);
    cout<<ans<<'\n';
    return 0;
}
 
谈判

 思路:一共要进行 n-1 步,只要保证每次合并最小的两个部落就能保证总代价最小。
 总操作数一定情况下的最小代价模型。我们知道这里一共需要进行的操作次数一定是n-1次,那么贪心地想,如果每次选择代价最小的两个部落合并,不仅可以使得当前代价最小,还可以使得后续合并的代价也尽可能小。
 部落大小通过优先队列来维护。
#include<iostream>
#include<queue>
using namespace std;
using ll = long long;
priority_queue<ll,vector<ll>,greater<ll>> pq;
int main( ){
    int n;cin>>n;
    for(int i = 0;i<n;i++){
        ll x;cin>>x;
        pq.push(x);
    }
    ll ans=0;
    while(pq.size()>1){
        ll x=pq.top();pq.pop();
        ll y=pq.top();pq.pop();
        ans+=x+y;
        pq.push(x+y);
    }
    cout<<ans<<'\n';
    return 1;
}
 
纪念品分组

 思路:要使分组尽可能少就尽可能进行两人分组,两人分组中一个多带一个小的会比两小+两多这种方案分组少,所以用一个多带一个小。因为两个多可能超出范围,然后就单独分组多分出组数。
 最少数目的贪心模型。
 为了使得组数最小,我们应该使得每一组内尽可能装两件礼物(最多只能装两件),尽量占满一组的容量。所以贪心策略是,每一个贵的礼物,带一个便宜的,因为带也是一组,不带也是一组,肯定选择带,且最贵的和最便宜的最容易占满一组。
#include<iostream>
using namespace std;
const int N = 1e5;
int a[N];
int main(){
    int w,n;cin>>w>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+1+n);
    int l=1,r=n,ans=0;
    while(l<=r){
        ans++;
        if(l==r){
            break;
        }
        if(a[l]+a[r]<=w){
            l++,r--;
        }else r--;
    }
    cout<<ans<<'\n';
    return 0;
}
                

















