zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    图片上传-下载-删除等图片管理的若干经验总结3-单一业务场景的完整解决方案
    图片上传-下载-删除等图片管理的若干经验总结2
    HDU 1195 Open the Lock
    HDU 1690 Bus System
    HDU 2647 Reward
    HDU 2680 Choose the best route
    HDU 1596 find the safest road
    POJ 1904 King's Quest
    CDOJ 889 Battle for Silver
    CDOJ 888 Absurdistan Roads
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12988497.html
Copyright © 2011-2022 走看看