zoukankan      html  css  js  c++  java
  • Codeforces Round #398 (div.2)简要题解

    这场cf时间特别好,周六下午,于是就打了打(谁叫我永远1800上不去div1)

    比以前div2的题目更均衡了,没有太简单和太难的...好像B题难度高了很多,然后卡了很多人。

    然后我最后做了四题,E题感觉不会太难就是切不下来,还好前面几题A的快居然混了个RANK6,然后+204,终于上到紫名了......

    ---------我是分割线君

    A.Snacktower

    有一个1到n的全排列,按顺序每一秒会到达一个数,你要把它们从n到1叠起来,如果能叠,你就马上叠。

    比如n=3到达顺序312 ,那么你第一秒就叠3,第三秒叠21。

    没什么好说的,直接模拟。n<=10^5

    看到题目直接就写了个堆,根本没必要,好傻。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<map>
    using namespace std;
    inline int read()
    {
       int x=0,f=1;char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
       return x*f;
    }
    
    priority_queue<int> q;
    int n,nown;
    
    void check()
    {
        while(!q.empty()&&q.top()==nown)
        {
            printf("%d ",q.top());
            q.pop();nown--;
        }
    }
    
    int main()
    {
        n=read();nown=n;
        for(int i=1;i<=n;i++)
        {
            int x=read();
            if(x==nown)
                printf("%d ",x),nown--;
            else
                q.push(x);
            check();
            printf("
    ");
        }
        return 0;
    }

    B.The Queue

    有一个只从ts开到tt的地方,很多人来,每个人要呆t分钟做事情。一个人来的时候如果有人在做事情,他就排队。你是一个谦让的人,会让同时到的人排前面或者先做事情,问你从什么时候来等候时间最小。

    这道题卡了很多人.....

    很显然,直接枚举在那一个人的前一秒来,或者所有人之后来就可以了。

    对于开门之前的时候,设你在第i个人之前1s到,等候时间为(i-1)*t+(ts-你到的时间);

    对于开门之后的时候,维护队伍,以及从什么时候开始排队,设有tot个人排队,开始排队的时间为begin,等候时间为t*tot+begin-s[i]

    这样就没了,考的就是细节。

    还好写一次就过了,这题拉了挺多分......

    复杂度On

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<map>
    #define ll long long
    using namespace std;
    inline ll read()
    {
       ll x=0,f=1;char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
       return x*f;
    }
    
    ll s[100005];
    int n;
    ll tf,tt,t;
    ll beg,tot;
    ll ans=200000000000000LL,times=0;
    
    int main()
    {
        tf=read();tt=read();t=read();n=(int)read();tt-=t;
        for(int i=1;i<=n;i++) s[i]=read();
        int i=1;
        s[0]=-1;
        for(;s[i]<tf&&i<=n;i++)
        {
            if(s[i]==s[i-1]) continue;
            if(ans>tf-(s[i]-1)+t*(i-1))
            {
                ans=tf-(s[i]-1)+t*(i-1);times=s[i]-1;
            }
        }
        beg=tf;tot=i-1;
        for(;i<=n&&s[i]<=tt;i++)
        {
            if(s[i]!=s[i-1])
            {
                if(beg+tot*t<=s[i]-1)
                {
                    printf("%I64d
    ",s[i]-1);
                    return 0;
                }
                else
                {
                    if(beg+tot*t-(s[i]-1)<ans)
                    {
                        ans=beg+tot*t-(s[i]-1);
                        times=s[i]-1;
                    }
                }
            }
            if(beg+tot*t<=s[i])
            {
                beg=s[i];tot=1;
            }
            else
                tot++;
        }
        if(beg+tot*t<=tt)
        {
            printf("%I64d
    ",beg+tot*t);
        }
        else
            printf("%I64d
    ",times);
        return 0;
    }

    C.Garland

    有一棵给定根的树,有点权,要求剪掉两条边使得三个联通块权值和相等。n<=1000000

    很水的题目,直接dfs,用S[i]表示点i和它的子树的权值和,能分就分了。

    最后判断一下即可。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read()
    {
       int  x=0,f=1;char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
       return x*f;
    }
    
    int n,rt,cnt=0;
    struct edge{
        int to,next;
    }e[4000005];
    int head[2000005];
    int tot=0,has=0;
    int s[2000005];
    
    int ans1=-1,ans2=-1;
    
    inline void ins(int f,int t)
    {
        e[++cnt].next=head[f];
        head[f]=cnt;
        e[cnt].to=t;
    }
    
    inline void insw(int f,int t){ins(f,t);ins(t,f);}
    
    void findans(int x)
    {
        if(has>2) return;
        else has++;
        if(ans1==-1) ans1=x;
        else if(ans2==-1) ans2=x;
    }
    
    void dfs(int x,int fa)
    {
        for(int i=head[x];i>0;i=e[i].next)
        {
            int v=e[i].to;
            if(v!=fa)
            {
                dfs(v,x);
                if(s[v]==tot) findans(v);
                else s[x]+=s[v];
            }
        }
    }
    
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
        {
            int u=read();s[i]=read();
            if(u==0) rt=i;
            else insw(i,u);
            tot+=s[i];
        }
        if(tot%3!=0) return 0*puts("-1");
        else tot/=3;
        dfs(rt,0);
        if(has>=2)
        printf("%d %d
    ",ans1,ans2);
        else puts("-1");
        return 0;
    }

    D.Cartons of milk

    冰箱有n瓶牛奶,商店有m瓶牛奶。

    每瓶牛奶一个保质期Ai,然后必须在保质期前喝完它,每天只能喝k瓶牛奶。求最多可以从商店买几瓶。n,m<=10^6,Ai<=10^7

    Ai范围很小,从后往前,让每一瓶牛奶尽可能晚喝掉,看看能否喝完冰箱里的。

    如果能喝完,就把商店的牛奶排序一下,从后往前对每一个还能喝的天,都尽可能的买,即可。复杂度(mlogm+Ai)

    应该有更简单的做法,我这个做法是现场想的,能做就直接做了。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read()
    {
       int  x=0,f=1;char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
       return x*f;
    }
    
    int n,m,maxn,k;
    int f[10000005];
    struct gg{
        int num,x;
    }s[10000005];
    int ans[1000005];
    int sum=0;
    
    bool cmp(gg x,gg y)
    {
        return x.x<y.x;
    }
    
    int main()
    {
        n=read();m=read();k=read();
        for(int i=1;i<=n;i++)
        {
            int x=read();++f[x];
            maxn=max(maxn,x);
        }
        for(int i=1;i<=m;i++)
        {
            s[i].x=read();s[i].num=i;
        }
        sort(s+1,s+m+1,cmp);
        for(int i=maxn;i;i--)
        {
            if(f[i]>k)
            {
                f[i-1]+=f[i]-k;f[i]=0;
            }
            else
                f[i]=k-f[i];
        }
        if(f[0]>k) return 0*puts("-1");
        else f[0]=k-f[0];
        int j=m;
        for(int i=maxn+1;i<=10000000;i++) f[i]=k;
        for(int i=10000000;i>=0;--i)
        {
            while(j>=1&&s[j].x>=i&&f[i]--)
            {
                ans[++sum]=s[j].num;j--;
            }
        }
        printf("%d
    ",sum);
        for(;sum;--sum)printf("%d ",ans[sum]);
        return 0;
    }

    E. Change-Free 

    一个人无限的纸币(100快)和有限的硬币(1块),他要在n天内每天买不同价格的产品Si,每天服务员都有一个不满意因数Wi,每次交易服务员会有一个不满意度

    为Wi*(找回的纸币的数量+找回的硬币的数量)。求一个付钱方案让总不满意度最小。n<=100000

    很显然每天要考虑怎么付钱的部分只有 Si%100,并且要不然就全部硬币付,要不然就一张纸币甩出来。

    其实这道题真的不难,但我就是没发现一个性质,就是每一天付硬币和不付硬币,硬币的差值是100......

    知道了这个就很简单了。

    我们从第一天到最后一天,每天都先购买它,然后把不购买会产生的不满意度存到堆里面。

    如果发现钱不够了,就去堆里找一个最小值,并且在那一天用纸币付钱,换取100个硬币。最后输出就行了。复杂度nlogn

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read()
    {
       int  x=0,f=1;char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
       while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
       return x*f;
    }
    
    int n,m;
    int s[100005];
    bool flag[100005];
    int w[100005];
    ll ans=0;
    
    struct node{
        ll f,num;
        friend bool operator < (node x,node y)
        {
            return x.f>y.f;
        }
    }newx;
    priority_queue<node> q;
    
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++)
            s[i]=read();
        for(int i=1;i<=n;i++) w[i]=read();
        for(int i=1;i<=n;i++)
        {
            if(s[i]%100==0) continue;
            m-=s[i]%100;
            ll x=(ll)(100-(s[i]%100))*w[i];
            q.push((node){x,i});
            while(m<0)
            {
                newx=q.top();q.pop();
                flag[newx.num]=1;
                m+=100;
                ans+=newx.f;
            }
        }
        printf("%I64d
    ",ans);
        for(int i=1;i<=n;i++)
        {
            if(s[i]%100==0) printf("%d 0
    ",s[i]/100);
            else if(flag[i]) printf("%d 0
    ",s[i]/100+1);
            else        printf("%d %d
    ",s[i]/100,s[i]%100);
        }
        return 0;
    }

    最后附上成绩图。

    FallDream代表秋之国向您问好! 欢迎您来我的博客www.cnblogs.com/FallDream
  • 相关阅读:
    .net 下比较蛋疼的word 表格转excel表格
    c# 使用oracle表、列备注信息实现高级 查询
    心理学习
    图片 照片 批量 压缩 格式转换 缩略图 旋转 复用办公助手
    人力资源系统技术标准
    年会 司庆 主体活动 婚庆 拓展 复用抽奖软件
    实施组合测试
    maven入门总结
    Apache FtpServer 的使用研究
    2022年Vivado HLS导出IP报错
  • 原文地址:https://www.cnblogs.com/FallDream/p/cf398.html
Copyright © 2011-2022 走看看