2023 Winter Camp - 贪心与二分(ACM集训)

B-Voting

题意:

支持D者可以使后面或前面任意支持R者永久不能参与投票。反之同理。

思路一:

使用队列进行模拟。

特点:

思路简单清晰(看到答案之后),但不易想到,需要积累经验;

代码如下:

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
char v[200005];
int n;
queue<int>r,d;
int main(){
    scanf("%d%s",&n,v);
    for(int i=0;i<n;i++){
        if(v[i]=='R')
            r.push(i);
        else
            d.push(i);
    }
    while(!r.empty()&&!d.empty()){
        if(r.front()<d.front())
            r.push(r.front()+n);
        else
            d.push(d.front()+n);
        d.pop();
        r.pop();    
    }
    if(r.empty())
        printf("D");
    else
        printf("R");
    return 0;
}

思路二:

枚举遍历投票过程;

特别注意:

区分可以消除的数量和实际的数量,如:d,nd;

模拟过程不止一次,要利用循环直到只剩一个人投票

特点:

思路简单,容易想到,但没有注意细节(见特别注意)极易卡住(一直WA);

代码如下:

#include<iostream>
#include<utility>
using namespace std;
int main() {
  int n;
  cin >> n;
  int nd = 0, nr = 0, d = 0, r = 0;
  pair<bool, char> table[200005];
  char ch;
  for (int i = 0; i < n; ++i) {
    cin >> ch;
    table[i].first = 1;
    table[i].second = ch;
    if (ch == 'D') {
      nd++;
    } else {
      nr++;
    }
  }
  while (nd&&nr) {
    for (int i = 0; i < n; i++) {
      if (table[i].first == 0) {
        continue;
      }
      if (table[i].second == 'D'&&nr) {
        if (r != 0) {
          table[i].first = 0;
          r--;
          nd--;
        } else {
          d++;
        }
      }
      if (table[i].second == 'R'&&nd) {
        if (d != 0) {
          table[i].first = 0;
          d--;
          nr--;
        } else {
          r++;
        }
      }
    }
  }
  if (nd) {
    cout << "D";
  } else {
    cout << "R";
  }
  return 0;
}

C-K-Dominant Character

题意:

在字符串s中找到一个数字k保证s字符串中k长度的子字符串都含有同一个字母。

思路:

遍历a到z,然后依次找出出现本字母的最小长度。

代码如下:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
    string s;
    cin>>s;
    int l=s.size();
    char m='a';
    int k1=INT_MAX;
    for(int i=0;i<26;i++){
        int k2=0;
        char ma=m+i;
        
        int link=1;
        for(int j=0;j<l;j++){
            if(s[j]==ma) link=1;
            else link++;
            k2=max(link,k2);
            
        }
        k1=min(k1,k2);
    }
    cout<<k1<<endl;
    return 0;
}

D-Frodo and pillows

题意:

n个人,m个枕头,frodo在第k个床;

分枕头使得frodo获得最多枕头并输出;

相邻两个人枕头差小于2;

思路:

对frodo所获枕头数进行二分查找;

特别注意:可能存在mid不够递减的情况;要分情况讨论赋值;

代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,ans;
bool check(int x) 
{
    int s1=0,s2=0;
    if(x>=k)
    {
        s1=(x*2-k+1)*(k)/2;
    }
    else
    {
        s1=(1+x)*x/2+k-x;
    }
    int k1=n-k+1;
    if(x>=k1)
    {
        s2=(x*2-k1+1)*(k1)/2;
    }
    else
    {
        s2=(1+x)*x/2+k1-x;
    }
    if(s1+s2-x<=m) return 1;
    else return 0;
}
signed main()
{
    cin>>n>>m>>k;
    int l=1,r=m;
    while(l<=r)//二分
    {
        int mid=(l+r)/2;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    cout<<ans;
}

E-Energy exchange

题意:

需要将能量传递让所有电池电量相等,但每次都要损失k%。

思路:

计算出多出电量和缺少电量的总和;

如果缺少电量正好比多出电量损失 k% ,那么答案就是当前单个电量。

需要二分枚举单个电量的值即可。

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k;
double a[N];
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%lf",&a[i]);
    }
    // 二分
    double l=0,r=1e3;
    while(r-l>1e-8){
        double mid=(r+l)/2;
        double s1=0,s2=0;
        for(int i=1;i<=n;i++){
            if(a[i]<mid) s1+=mid-a[i];
            else s2+=a[i]-mid;
        }
        if(s1>s2*(100-k)/100) r=mid;
        else l=mid;
    }
    printf("%.8lf",l);
    return 0;
}

总结:

该组题目主要用到贪心和二分,许多题目思路新颖,值得细细推敲;

PS:

如果对你有帮助的话,点个赞谢谢喵!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值