Educational Codeforces Round 88 (Rated for Div. 2) A-D题解

链接:https://codeforces.com/contest/1359

A. Berland Poker

题意:

现在有$n$张牌,$m$张王,共有$k$个人,每个人分得$\frac{k}{n}$张牌,你的得分是你手中王牌的个数减去其余人中拥有最多王牌的个数,求最大得分

思路:

分类讨论一下即可,如果$m$大于$\left \lceil \frac{k}{n}\right \rceil$,那么答案就为$\left \lceil \frac{m-\left \lceil \frac{k}{n}\right \rceil}{k-1}\right \rceil$

否则,答案就为$m$

#include<iostream>
#include<algorithm>
 using namespace std;
 typedef long long ll;
 int main()
 {
     int t;
     cin>>t;
     while(t--){
         int n,m,k;
         cin>>n>>m>>k;
         int num=n/k;
         if(n%k!=0) num++;
         if(m>num){
             int cnt=(m-num)/(k-1);
             if((m-num)%(k-1)!=0) cnt++;
             cout<<num-cnt<<endl;
         } 
        else cout<<m<<endl;
     }
     return 0;
 }
View Code

 B. New Theatre Square

题意:

在$n*m$的二维区域内有黑色和白色两种瓷砖,现在你要覆盖白色的瓷砖,你可以选择花费$x$元覆盖一个瓷砖,也可以选择花$y$元覆盖同一行的连续两个瓷砖,求覆盖掉所有白色瓷砖的最小花费

思路:

如果$2*x≤y$的话,答案就为$x*num$,$num$为白色瓷砖的个数

否则,就遍历整个区域,如果$(x,y)$位置是白色瓷砖,那么就观察$(x,y+1)$处,如果也是白色瓷砖就花费$y$元将两块瓷砖同时覆盖,否则就花$x$元

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+5;
char a[N][N];
int main(){
    int t;
    cin>>t;
    while(t--){
        ll n,m,x,y,num=0; 
        cin>>n>>m>>x>>y; 
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                cin>>a[i][j];
                if(a[i][j]=='.') 
                    num++;
            }
        if(x*2<=y) cout<<num*x<<endl;
        else {
            ll ans=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++){
                    if(a[i][j]=='.'){
                        if(j<m&&a[i][j+1]==a[i][j]) ans+=y,j++;
                    else ans+=x;
                    }
                    
                }
            cout<<ans<<endl;
        }
    }
    return 0;
}
View Code

 C. Mixing Water

题意:

热水的温度为$h$,冷水的温度为$c$,目标温度为$t$,现在不停依次倒入热水,冷水,热水,冷水...,求倒入几次后混合水点的温度最接近$t$(混合水的温度为倒入的水的温度总和/倒入的次数)

思路:

可以发现倒入冷水后的温度始终都为$(h+c)/2$,所以答案不可能为除$2$以外的偶数,所以当$t≤(h+c)/2$时,答案一定为$2$

再观察倒入热水后的规律,发现倒入热水之后,温度的函数为$(x*h+h+x*c)/(2*x+1)$($x$是倒入了几次热水,并且从$0$开始),而且这个函数是以递减变化的

因此我们可以二分倒入热水的次数,找到最后一次水的温度大于等于$t$的时刻$tim$,再与$tim+1$时刻进行比较看哪个值更接近$t$,就能求出需要倒几次热水

#include<bits/stdc++.h>
#define ll long long
using namespace std;
 long double h,c,t,sb;
 long double pd(int x){
      return (h*x+h+c*x)/(2*x+1);
}
int main(){
    ll p; 
    cin>>p;
    while(p--){
        cin>>h>>c>>t; 
        sb=(h+c)/2;
        if(sb>=t) cout<<2<<endl;
        else{
            int l=0,r=1e9;
            while(l<r){
                ll mid=(r+l+1)/2;
                if(pd(mid)>=t) l=mid;
                else r=mid-1;
            } 
            if(fabs(pd(r+1)-t)<fabs(pd(r)-t))
                r++;
            cout<<2*r+1<<endl;    
        }
    }    
    return 0;
}
View Code

D. Yet Another Yet Another Task

题意:

给一个序列,你可以选择一个子段,要求去掉子段最大值后的和最大,求出这个最大值

思路:

可以发现$-30≤n≤30$,那么我们可以在$1-30$的范围内枚举区间的最大值,因为如果当区间最大值为负数或$0$时,区间的其他数肯定也为负数或者为$0$,那么选择这样的一段是没有意义的,最大值肯定为$0$

在枚举区间最大值时,我们记录下(最大子段和-枚举值)的最大值,遇到比枚举值大的数的时候,就将累加的数清零即可

#include<iostream>
#include<algorithm>
 using namespace std;
 const int maxn=1e5+10;
 int a[maxn];
 int main()
 {
     int n,flag=0;
     scanf("%d",&n);
     for(int i=1;i<=n;i++)
         scanf("%d",&a[i]);
    int ans=0,cnt=0;
    for(int i=1;i<=30;i++){
        cnt=0;
        for(int j=1;j<=n;j++){
            if(a[j]>i){
                cnt=0;
                continue;
            }
            cnt+=a[j];
            if(cnt<0) cnt=0;
            ans=max(cnt-i,ans);
        }
    }
    cout<<ans;
    return 0;
 }
View Code

 

posted @ 2020-05-29 14:30  overrate_wsj  阅读(528)  评论(4编辑  收藏  举报