zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 80

    EduRound 80

    A

    题意

    有一项任务,要求在n天内完成,不优化的话需要d天,如果用 x 天来优化则可以变成 d/(x+1) (向下取整)天。即总共花 x+d/(x+1) 天,求是否可以按要求完成。

    思路

    总时间很明显是个凹函数,考虑三分,但是由于存在向下取整,所以不是严格凹函数,所以不能三分。但是可以直接求导,求导一下得到最优的xsqrt(4d)/2-1

    代码

    #include<bits/stdc++.h>
    using namespace std;
     
    int n,d;
     
    int f(int x)
    {
        return x+d/(x+1)+(d%(x+1)>0);
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&d);
            int x=int(sqrt(4.0*d)/2.0-1);
            printf(f(x)<=n?"YES
    ":"NO
    ");
        }
    }
    

    B

    题意

    给出A,B寻找有多少对a,b, a∈[1,A],b∈[1,B] 使得 ab+a+b=a拼接b 。拼接即两数连接在一起得到新数,如 6拼接9得到69

    思路

    打表找规律,发现b9,99,998,......a 任选,所以计算一下 [1,B] 有多少 9... 这种数,再乘 A 就是答案。

    代码

    #include<bits/stdc++.h>
    using namespace std;
     
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            long long a,b,k=0,cur=9;
            scanf("%I64d%I64d",&a,&b);
            while(cur<=b)
            {
                k++;
                cur=cur*10+9;
            }
            printf("%I64d
    ",a*k);
        }
    }
    

    C

    题意

    给出n,m,求有多少对数组a,b满足:

    • a,b长度均为m
    • a,b中所有元素均∈[1,n](可重复)
    • 所有对应位置元素有ai<=bi
    • a保证单调不降
    • b保证单调不增

    思路

    分开考虑比较复杂,所以考虑a,b合起来,将a正序排列,b倒序排列接在a后面,则可以得到一个c,使得c满足长度为2m,且单调不降。则问题转化为 [1,n] 中选择 2m 个可重复的数使得构成一个单调不降序列。可以用两种方法解决

    1. DP:状态定义为dp[i][j]表示c中第i位为j的选法个数。因为保持单调不降,所以转移就由前一位小于等于j的状态转移而来。

    2. 组合数学:假设 [1,n]i 个数选择 xi 次,则问题转化为方程

      [sum_{i=1}^nx_i=2m ]

      用隔板法解决。因为可选多次,可不选,所以增加n个,答案就是

      [C_{2m+n-1}^{n-1} ]

    代码

    DP

    #include<bits/stdc++.h>
    using namespace std;
    const int MAX=2e3+3;
    const int mod=1e9+7;
     
    int dp[25][MAX];
     
    int main()
    {
        int n,m,res=0;
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            dp[1][i]=1;
        for(int i=2; i<=2*m; i++)
            for(int j=0; j<n; j++)
                for(int k=0; k<=j; k++)
                    dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;
        for(int i=0;i<n;i++)
            res=(res+dp[2*m][i])%mod;
        printf("%d
    ",(res+mod)%mod);
    }
    

    排列组合

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
     
    const ll mod=1e9+7;
     
    ll qpow(ll x,ll k)
    {
        ll res=1;
        while(k)
        {
            if(k&1)
                res=res*x%mod;
            k>>=1;
            x=x*x%mod;
        }
        return res;
    }
    ll inv(ll x){return qpow(x,mod-2);}
    ll jc(ll x)
    {
        ll res=1;
        while(x){res=res*x%mod;x--;}
        return res;
    }
     
    int main()
    {
        ll n,m,a,b;
        scanf("%I64d%I64d",&n,&m);
        a=2*m+n-1;
        b=n-1;
        n=jc(a);
        m=jc(b)*jc(a-b)%mod;
        printf("%I64d
    ",n*inv(m)%mod);
    }
    

    D

    题意

    给出n个数组,长度均为m,可以选两个数组(可以相同),然后对应位置取max得到一个新数组,求如何选择使得最后得到的新数组中的最小值最大。

    思路

    最小值最大很容易想到二分答案,所以问题就是如何快速判断一个解是否可行。因为m很小,所以容易想到状态压缩。假设当前判断答案x。对于任意一个数组a,如果a[i]>=x,则记此位为1,否则记为0,则所以数组都可以压缩成最多255的数,所以状态总共有255种,可以O(n^2)的判断两个数组是否可行,可行即二者按位或得到全为1

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAX=3e5+5;
     
    int n,m,ra,rb,a[MAX][10];
    int mp[(1<<8)];
     
    bool check(int x)
    {
        memset(mp,0,sizeof mp);
        for(int i=0; i<n; i++)
        {
            int cur=0;
            for(int j=0; j<m; j++)
                cur|=(a[i][j]>=x)<<(m-j-1);
            mp[cur]=i+1;
        }
        int tot=(1<<m);
        for(int i=0; i<tot; i++)
            for(int j=0; j<tot; j++)
                if(mp[i]&&mp[j]&&((i|j)==tot-1))
                {
                    ra=mp[i],rb=mp[j];
                    return 1;
                }
        return 0;
    }
     
    int main()
    {
        int L=0,R=0,res;
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
                scanf("%d",&a[i][j]),R=max(R,a[i][j]);
        while(L<=R)
        {
            int mid=(L+R)>>1;
            if(check(mid))
            {
                res=mid;
                L=mid+1;
            }
            else
                R=mid-1;
        }
        if(ra>rb)swap(ra,rb);
        printf("%d %d
    ",ra,rb);
    }
    

    E

    题意

    给一个长度为n的排列,初始为1-nm个操作,每次选一个x,然后把xx原来所在位置p[x]提到第一位,1-p[x]-1的数依次往后推,求1-n在操作过程中位置能达到的最大值和最小值

    思路

    将题目中操转化为在排列前面预留m个位置,然后每次操作将p[x]置零,然后将最左边的位置改为x,这样就避免了往后推的操作。然后min就是1或者最初的位置,max就是位于前面的数的数量。如果x没有被提到第一位,则min不会变化,max只会增加,所以用树状数组维护,改变了的x在操作过程中更新,没有改变的x在所有操作结束后更新。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAX=3e5+5;
     
    int n,m,c[MAX<<1],p[MAX],minn[MAX],maxx[MAX];
     
    void add(int x,int k)
    {
        for(;x<=n+m;x+=x&-x)
            c[x]+=k;
    }
    int query(int x)
    {
        int sum=0;
        for(;x;x-=x&-x)
            sum+=c[x];
        return sum;
    }
     
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            p[i]=i+m;
            minn[i]=i;
            maxx[i]=i;
            add(p[i],1);
        }
        for(int i=0;i<m;i++)
        {
            int x;
            scanf("%d",&x);
            maxx[x]=max(maxx[x],query(p[x]));
            minn[x]=1;
            add(p[x],-1);
            p[x]=m-i;
            add(p[x],1);
        }
        for(int i=1;i<=n;i++)
        {
            maxx[i]=max(maxx[i],query(p[i]));
            printf("%d %d
    ",minn[i],maxx[i]);
        }
    }
    
  • 相关阅读:
    JDBC07-----代码重构之封装DBCUtils工具类
    JDBC06-----数据库连接池与配置文件
    JDBC05----事务与批处理
    JDBC04----预编译语句介绍
    JDBC03----DAO思想
    数据的序列化,持久化,归档
    苹果官方的图标大小的调整
    UIColletionView 的属性与常用方法介绍
    IOS学习笔记25—HTTP操作之ASIHTTPRequest
    IOS UI segmentedControl UISegmentedControl 常见属性和用法
  • 原文地址:https://www.cnblogs.com/cryingrain/p/12535449.html
Copyright © 2011-2022 走看看