CodeForces Edu Round 88 (A-E)

Posted bakacirno

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces Edu Round 88 (A-E)相关的知识,希望对你有一定的参考价值。

传送门

A.Berland Poker

首先算一下最多的那个人能拿多少 Joker,应该是 (x=min(n/k,m)) 张。那么剩下 (m-x) 张 joker 均分给剩下的 (n-1) 个人,这样可以保证第 (2) 多的人尽量少,所以剩下的人最多能有 (other=(m-x)/(n-1)+(bool)((m-x)%(n-1))) 张 joker,答案就是 (x-other)

include <bits/stdc++.h>
using namespace std;
int n,m,k;

void solve(){
    n=read(),m=read(),k=read();
    int maxv=min(n/k,m);
    int other=(m-maxv)/(k-1)+((m-maxv)%(k-1)?1:0);
    printf("%d
",maxv-other);
}

int main(){
    int T=read();
    while(T--) solve();
    return 0;
}

B. New Theatre Square【贪心】

题意

给一个 (n imes m) 矩阵,有"."或"*",有两种地砖,尺寸分别为 (1 imes 1)(1 imes 2),价格分别为 (x)(y)。要求将所有 "." 覆盖,问最少需要多少钱。

思路

如果 (x*2le y),那么直接用 (1 imes 1) 的地砖铺满就好。
否则先用 (1 imes 2) 的地砖铺,然后再用 (1 imes 1) 的地砖将漏补上。

代码

#include <bits/stdc++.h>
using namespace std;
int n,m,x,y;
char g[110][1010];

void solve(){
    n=read(),m=read(),x=read(),y=read();
    for(int i=1;i<=n;i++) scanf("%s",g[i]+1);
    int ans=0;
    if(x*2<=y){
        for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)ans+=(g[i][j]==‘.‘)*x;
        return (void)printf("%d
",ans);
    }
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
        if(j<m&&g[i][j]==‘.‘&&g[i][j+1]==‘.‘)
            ans+=y,g[i][j]=g[i][j+1]=‘*‘;
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)ans+=(g[i][j]==‘.‘)*x;
    printf("%d
",ans);
}

int main(){
    int T=read();
    while(T--) solve();
    return 0;
}

C. Mixing Water【数学?】

题意

给你两种温度的水,一种温度为 (h),一种温度为 (c)。你依照 (h,c,h,c,...) 的顺序向容器里倒水,问最少多少杯水可以使得容器中水的温度最接近 (t)(h,c,t) 满足 (cle tle h)

思路

可以发现以这个顺序,无论倒多少杯水,最后的温度一定大于等于 ((h+c)/2),所以如果 (2*tle h+c),答案直接为 (2)
否则,设要倒 (x)(c)(x+1)(h),那么当前温度为:(frac{(x+1)h+xc}{2x+1}=>frac{h+c}{2}+frac{h-c}{4x+2})
解方程

[h+c+frac{h-c}{2x+1}=2t ]

得出来 (x) 大概是个分数,取整之后,比较 (x)(x+1) 哪个对应最接近 (t) 的温度。然后计算答案。

代码

#include <bits/stdc++.h>
using namespace std;
int h,c,t;

void solve(){
    scanf("%d%d%d",&h,&c,&t);
    if(h+c>=2*t) return (void)printf("2
");
    double x=(1.0*(h-c)/(2*t-h-c)-1)/2;
    int x1=(int)x,x2=x1+1,ans;
    double t1=(h+c+1.0*(h-c)/(2*x1+1))/2;
    double t2=(h+c+1.0*(h-c)/(2*x2+1))/2;
    if(fabs(t1-t)<=fabs(t2-t)) ans=x1*2+1;
    else ans=x2*2+1;
    printf("%d
",ans);
}

int main(){
    int T=read();
    while(T--) solve();
    return 0;
}

D. Yet Another Yet Another Task【ST+二分】

题意

给数列 (a_1,a_2,...,a_n),计算一段连续区间之和减去该区间最大值的最大值。

思路

因为 (a_i) 的值域限制,可以用最大字段和的思路来做。但本菜鸡没想到,所以用了 ST+二分 的笨办法,比赛的时候还写疵了。
对于每个 (a_i) 找到以它为最大值的最长区间,这个显然可以用 ST表+二分 找到。假设为 L,R。那么此时要从中选出和最大且包含 (a[i]) 的一段的和值,用 (s[i]) 表示前缀和,那么这个最大的和值,就是 (s[i],...,s[R]) 的最大值,减去 (s[L-1],...,s[i-1]) 的最小值。所以这里同样可以用ST表实现。

代码

#include <bits/stdc++.h>
using namespace std;
int n,a[N],st[N][21],minv[N][21],maxv[N][21],s[N];

int smax(int l,int r){
    if(l==r) return a[l];
    int k=log2(r-l);
    return max(st[l][k],st[r-(1<<k)][k]);
}
int maxsum(int l,int r){
    if(l==r) return s[l];
    int k=log2(r-l);
    return max(maxv[l][k],maxv[r-(1<<k)][k]);
}
int minsum(int l,int r){
    if(l==r) return s[l];
    int k=log2(r-l);
    return min(minv[l][k],minv[r-(1<<k)][k]);
}

int main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read(),s[i]=s[i-1]+a[i];
    for(int i=0;i<=n;i++) 
        st[i][0]=max(a[i],a[i+1]),
        maxv[i][0]=max(s[i],s[i+1]),
        minv[i][0]=min(s[i],s[i+1]);
    for(int j=1;j<=20;j++)
        for(int i=0;i+(1<<j)<=n;i++)
            st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]),
            maxv[i][j]=max(maxv[i][j-1],maxv[i+(1<<j-1)][j-1]),
            minv[i][j]=min(minv[i][j-1],minv[i+(1<<j-1)][j-1]);
    int ans=0;
    for(int i=1,l,r,L,R;i<=n;i++){
        l=1,r=i;
        while(l<r){
            int mid=(l+r)/2;
            if(smax(mid,i)<=a[i]) r=mid;
            else l=mid+1;
        }
        L=l,l=i,r=n;
        while(l<r){
            int mid=(l+r+1)/2;
            if(smax(i,mid)<=a[i]) l=mid;
            else r=mid-1;
        }
        R=l;
        int temp=maxsum(i,R)-minsum(L-1,i-1)-a[i];
        ans=max(ans,temp);
    }
    printf("%d
",ans);
    return 0;
}

E. Modular Stability

题意

问从 (1,...,n) 中抽 (k) 个数,对任意排列 (p),使得 (x%a_{p_1}%a_{p_2}%...%a_{p_3}) 相同,问这个 (k) 个数由多少种选择。

思路

补题的时候看到这道题,就这?比 D 题简单啊。
显然要满足条件,这 (k) 个数中,有 (1) 个数肯定是其他 (k-1) 个数的约数。
那么做法就很简单了,首先枚举这 (1) 个数,然后算出它倍数的个数 (m),那么就要从这这 (m) 个数中选出 (k-1) 个数,所以这 (1) 个数对于答案的贡献为 (C_m^{k-1})

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=5e5+10;
const int MOD=998244353;
inline LL qpow(LL x,LL k=MOD-2,LL mod=MOD){LL res=1;while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;}
LL n,k,fac[N]={1};

LL C(int n,int m){
    if(m>n) return 0;
    return fac[n]*qpow(fac[m])%MOD*qpow(fac[n-m])%MOD;
}

int main(){
    n=read(),k=read();
    for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD;
    if(n<k) return printf("0
"),0;
    LL ans=0;
    for(int i=1;i<=n;i++){
        int num=n/i;
        if(num<k) break;
        ans=(ans+C(num-1,k-1))%MOD;
    }
    printf("%lld
",ans);
    return 0;
}






以上是关于CodeForces Edu Round 88 (A-E)的主要内容,如果未能解决你的问题,请参考以下文章

2020.5.28 Educational Codeforces Round 88 比赛记录

2020.5.28 Educational Codeforces Round 88 比赛记录

Educational Codeforces Round 88 (Rated for Div. 2) E. Modular Stability

Educational Codeforces Round 88 (Rated for Div. 2) E. Modular Stability

Educational Codeforces Round 88 (Rated for Div. 2) B. New Theatre Square

Educational Codeforces Round 88 (Rated for Div. 2) B. New Theatre Square