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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM