• 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;
    }
    
  • 相关阅读:
    H5 video播放视频遇到的问题
    IIS域名转发
    IIS Tomcat共享80端口
    C# 操作注册表WindowsRegistry
    Owin Middleware如何在IIS集成管道中执行
    如何定义一个有效的OWIN Startup Class
    mysql 数据库的备份与还原 at winows
    windows查看端口占用
    asp.net 二级域名表单认证情况下共享Cookie
    c# 多线程使用队列顺序写日志的类 (需要再优化)
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12988497.html
Copyright © 2020-2023  润新知