20180714练习赛 [CF]EDU ROUND3 EASY

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CQBZLYTina/article/details/81975460

A - USB Flash Drives CodeForces - 609A
B - The Best Gift CodeForces - 609B
C - Load Balancing CodeForces - 609C
D - Gadgets for dollars and pounds CodeForces - 609D
E - Minimum spanning tree for each edge CodeForces - 609E

A

水题 没什么好说的(也不用纠结)

B

有n本书分属于m类,每本都不同,现要选取两本种类不同的书,问有多少种选择方案

就是模拟题了 但实现有点考人 之前直接O(n^2)判断 T过一次
毕竟N是200000的
关于运行时间的判断:
时限1s时,10^6基本可以过,10^7有点儿悬,10^8就很有可能会T
那我这种暴力都10^10了,怎么可能会过
优化一下,注意到m的范围非常小,只有10,我们统计每一类书的数量然后枚举选哪一类书和哪一类书,根据乘法原理就可以出解了。

观察和预估能力很重要啊!!!

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200005
int a[MAXN],num[20];
int N,M,ans=0;
int main()
{
    scanf("%d %d",&N,&M);
    for(int i=1;i<=N;i++)
    {
        scanf("%d",&a[i]);
        num[a[i]]++;
    }

    for(int i=1;i<=M;i++)
        for(int j=i+1;j<=M;j++)
            ans+=num[i]*num[j];
    printf("%d\n",ans);
}

C

有n台电脑,他们的性能分别是x1,x2…xn,高性能电脑可以每秒将自己的性能传递给低性能电脑,
即自己-1,低性能+1.问最少需要多少秒才能使它们达到平衡。(也就是它们之间的差距最大为1)

最后的序列每个数肯定是平均数或平均数+1
算出这两个数 依次遍历一遍,看与这两个数更近的那个还差多少
但这么做会WA 因为可能会“对不上数”,要保证变化后的序列总和仍然不变
sum%n 表示的就是每个数为“平均数”之后还剩了多少个1,也就是还有这么多个数转化后值为“平均数”+1,显然让更大的数去变成“平均数”+1

然而我在考场上没想到这个 做法是:让小的数变成“平均数”,让大的数变成“平均数”+1,然后去它们的代价的最大值
Like this:

int ans1=0,ans2=0;
    for(int i=1;i<=N;i++)
    {
        if(a[i]<l) ans1+=l-a[i];
        if(a[i]>r) ans2+=a[i]-r;
    }

但我这么写其实没有上面那种好理解 它的思想其实就是:把所有低于平均值的数提升到平均值,需要总共加ans1,也就是大于平均数的值,要减去ans1才能满足。而让大于平均数的值符合调价(变成“平均数”+1)又至少要减去ans2才能满足。同时要满足两种情况,只能取最大值。而ans1和ans2的差,实际上就是不能去最优的数的个数(小于“平均数”的值变成“平均数”+1,大于平均数的值变成平均数)

#include<cstdio>
#define MAXN 100005
int N,a[MAXN],ans;
int Max(int x,int y)
{
    if(x>y) return x;
        else return y;
}
int main()
{
    int sum=0,l=0,r=0;
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
    {
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    l=sum/N;
    r=l+1;
    int ans1=0,ans2=0;
    for(int i=1;i<=N;i++)
    {
        if(a[i]<l) ans1+=l-a[i];
        if(a[i]>r) ans2+=a[i]-r;
    }
    ans=Max(ans1,ans2);
    printf("%d\n",ans);
}

D

二分
细节有点多,想通了后也挺简单的
调了很久 发现二分的初始边界不够大。。。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define LL long long
#define INF 1000000000
struct node{
    int type,id;
    LL need,bur;
}g[MAXN];
int n,m,k;
LL s;
int a[MAXN],p[MAXN],d[MAXN];
struct no{
    int id,day;
}ans[MAXN];
bool cmp(node x,node y)
{
    return x.bur<y.bur;
}
bool check(int mid)
{
    int pd=1,pp=1;
    for(int i=2;i<=mid;i++)
    {
        if(d[i]<d[pd])
            pd=i;
        if(p[i]<p[pp])
            pp=i;
    }
    for(int i=1;i<=m;i++)
    {
        if(g[i].type==1) g[i].bur=d[pd]*g[i].need;
        else g[i].bur=p[pp]*g[i].need;
    }
    sort(g+1,g+m+1,cmp);
    LL res=0;
    for(int i=1;i<=k;i++)
        res+=g[i].bur;
    if(res>s) return 0;
    for(int i=1;i<=k;i++)
    {
        ans[i].id=g[i].id;
        if(g[i].type==1) ans[i].day=pd;
            else ans[i].day=pp;
    }
    return 1;
}
int main()
{
    scanf("%d %d %d %lld",&n,&m,&k,&s);
    for(int i=1;i<=n;i++)
        scanf("%d",&d[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&p[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d %lld",&g[i].type,&g[i].need);
        g[i].id=i;
    }
    int l=0,r=n+1;
    bool f=0;
    while(l+1<r)
    {
        int mid=(r-l)/2+l;
        if(check(mid))
            r=mid,f=1;
        else l=mid;
    }
    if(!f) 
    {
        printf("-1\n");
        return 0;
    }
    printf("%d\n",r);
    for(int i=1;i<=k;i++)
        printf("%d %d\n",ans[i].id,ans[i].day);
}

E

求含有每条边的最小生成树

考场上想出来了正解 但是不会打。。。
就是先求最小生成树,最小生成树上的边get√
然后非最小生成树上的边就在生成树上连起来,然后破圈。
但是我不会打呀啊啊啊,破圈从来没打过呀啊啊啊qwq

猜你喜欢

转载自blog.csdn.net/CQBZLYTina/article/details/81975460