Educational Codeforces Round 88 (Rated for Div. 2) 1359 A~D題解

鴿了好多場的題解,這場不鴿了.

關鍵這場我也沒打呀

Cue一下隊友鏈接:

核心選手:https://me.csdn.net/qq_43559193

核心選手:https://me.csdn.net/weixin_43916298

比賽鏈接:https://codeforces.com/contest/1359

目錄

比賽鏈接:https://codeforces.com/contest/1359

A. Berland Poker

題目大意:

題目思路:

Code:

B. New Theatre Square

題目大意:

題目思路:

Code:

C. Mixing Water

題目大意:

題目思路:

Code:

D. Yet Another Yet Another Task

題目大意:

題目思路:

Code:


A. Berland Poker

題目大意:

具體沒怎麼讀,看了看樣例和解釋,大概理解了個意思,瞎寫。

題目大體意思應該是 求一個每人手中小丑牌的最大值 - 其他人中最小值 (大概是這樣,我也沒讀題)

題目思路:

然後就很水了呀:

如果小丑牌小於等於每個人應得的手牌,那麼肯定是小丑牌數量。

否則一個人全拿,剩下的平分(上取整),然後求一下答案

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-7;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
int main(){
    int T;scanf("%d",&T);
    while(T--){
        read(n);read(m);read(p);
        ll temp = n/p;
        if(temp>=m) printf("%lld\n",m);
        else{
            ll diff = m - temp;
            printf("%lld\n",temp - ((diff+p-2)/(p-1)));
        }
    }
    return 0;

}
/**
* 10 *
0000 1111
**/

B. New Theatre Square

題目大意:

輸入n,m,x,y 代表有n*m的矩陣,塗1*1的格子需要x,塗1*2的格子需要y,問最少花費多少使得圖中所有的'.'均被染色

題目思路:

首先可以得出 如果2*x <= y ,ans = ‘.’的個數 * x

否則,全塗1 * 2 剩下的塗1,然後可以發現 1*2只可以橫着塗,那麼就遍歷一下就行了

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-7;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
char str[1005][1005];
vector<char>v;
int main(){
    int T;scanf("%d",&T);
    while(T--){
        ll x,y;read(n);read(m);
        read(x);read(y);
        for(int i=1;i<=n;i++) scanf("%s",str[i]+1);
        int cot = 0;
        for(int i=1;i<=n;i++){
            for(int k=1;k<=m;k++){
                if(str[i][k]=='.') cot ++;
            }
        }
        if(2*x <= y) printf("%lld\n",1ll*cot*x);
        else{
            ll ans = 0;
            for(int i=1;i<=n;i++){
                int cnt = 1;
                for(int k=2;k<=m;k++){
                    if(str[i][k]!=str[i][k-1]){
                        int res = cnt%2;
                        if(str[i][k]=='*')
                            ans+=(cnt/2)*y+res*x;
                        cnt = 1;
                    }
                    else cnt++;
                }
                int res = cnt%2;
                if(str[i][m]=='.')
                    ans+=(cnt/2)*y+res*x;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
/**
* 10 *
0000 1111
**/

C. Mixing Water

題目大意:

輸入a,b,t,a代表一杯熱水的溫度,b代表一杯冷水的溫度,每次可以倒一杯熱水後,再倒一杯冷水,然後..依次類推,最終的溫度是這些的平均值,問最少倒幾次使得其可以最接近溫度t

題目思路:

首先兩種情況:

假設熱水到了x次

1.假設倒的次數爲偶數,那麼此時t = \frac{x*a+x*b}{2*x} = \frac{a+b}{2},所以次數爲偶數時不需要考慮,只需要記錄2的答案就可以

2.假設倒的次數爲奇數,那麼此時t = \frac{(x+1)*a+x*b}{2*x+1},所以此時無需多言,盲猜具有單調性,直接二分寫,發現確實具有單調性...,剩下的就是二分怎麼寫了。

這題正解應該是解方程吧..二分直接卡死精度了,精度到1e-15才過

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-15;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
double cal(ll x){
    double tempx = x/2+1,tempy = x/2;
    return (tempx*n+tempy*m)/(x*1.0);
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        read(n);read(m);read(p);
        if(2*p == n+m) printf("2\n");
        else if(n==p) printf("1\n");
        else{
            int ans = 2;
            double diff = abs((double)(n+m)*0.5-(double)p);
            ll l = 1, r = 1e9+7;
            double ans_left = -1,ans_right = -1;
            while(l<=r){
                ll mid = (l+r)/2;
                double res = cal(2*mid-1);
                if(res-p>eps){
                    ans_right = 2*mid-1;
                    l = mid+1;
                }
                else{
                    ans_left = 2*mid-1;
                    r = mid-1;
                }
            }
            if(ans_left!=-1)
                if(abs(cal(ans_left)-p)-diff<eps) ans = ans_left,diff = abs(cal(ans_left)-p);
            if(ans_right!=-1)
                if(abs(cal(ans_right)-p)-diff<eps) ans = ans_right,diff = abs(cal(ans_right)-p);
            printf("%d\n",ans);
        }
    }
    return 0;
}
/**
* 10 *
0000 1111
**/

D. Yet Another Yet Another Task

題目大意:

抽象一下:選擇一個區間,讓這個區間減去當前區間最大值,求這種答案的最大值

題目思路:

經典套路了,直接秒掉就可以了

枚舉一下最大值的位置,單調棧維護最大值可控區間,查一下前綴和的最大值最小值,計算答案就可以了。

本着優化算法的初衷,直接把區間查詢換成O1查詢的st表,124ms跑到起飛。

這題正解的話應該是枚舉30個值作爲最大值 複雜度30*n  不過st表預處理也就lgn的複雜度 ,複雜度20*n

所以,哪個好寫寫哪個咯

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=2e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-7;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m;
int st[maxn];
int pre[maxn],cur[maxn];//表示前方可以控制到多少,後方可以控制到多少。
ll num[maxn];
ll st_max[maxn][20],st_min[maxn][20];
ll lg[maxn];
ll f[maxn];
void work()
{
    ll cnt=0;
    for(int i=1;i<=n;i++)
        lg[i]=lg[i/2]+1;
    for(int i=0;i<=n;i++)
        st_max[i][0]=st_min[i][0]=f[i];
    for(int j=1;j<=25;j++)
        for(int i=0;i+(1<<j)-1<=n;i++){
            st_max[i][j]=max(st_max[i][j-1],st_max[i+(1<<(j-1))][j-1]);
            st_min[i][j]=min(st_min[i][j-1],st_min[i+(1<<(j-1))][j-1]);
        }
}
ll query_max(ll x,ll y)
{
    ll len=lg[y-x+1]-1;
    return max(st_max[x][len],st_max[y-(1<<len)+1][len]);//爲啥+1
}
ll query_min(ll x,ll y)
{
    ll len=lg[y-x+1]-1;
    return min(st_min[x][len],st_min[y-(1<<len)+1][len]);//爲啥+1
}
void get_min(){
    int bg=0;
    st[0]=0;
    for(int i=1;i<=n;i++){
        while(bg!=0&&num[i]>=num[st[bg]])
            bg--;
        pre[i]=st[bg];
        st[++bg]=i;
    }
    bg=0;
    st[0]=n+1;
    for(int i=n;i>=1;i--){
        while(bg!=0&&num[i]>=num[st[bg]]) 
            bg--;
        cur[i]=st[bg];
        st[++bg]=i;
    }
    for(int i=1;i<=n;i++) pre[i]++,cur[i]--;
}
int main(){

    read(n);
    for(int i=1;i<=n;i++){
        read(num[i]);
        f[i] = f[i-1] + num[i];
    }
    work();
    get_min();
    ll maxl = 0;
    for(int i=1;i<=n;i++){
        ll temp = query_max(i,cur[i]) - query_min(pre[i]-1,i-1);
        maxl = max(maxl,temp-num[i]);
    }
    printf("%lld\n",maxl);
    return 0;

}
/**
* 10 *
0000 1111
**/

下面看一下E題,哦數論或者組合數學呀,打擾了,爭取不鴿你。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章