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题,哦数论或者组合数学呀,打扰了,争取不鸽你。

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