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
  • 相关阅读:
    北京燃气IC卡充值笔记
    随机分析、随机控制等科目在量化投资、计算金融方向有哪些应用?
    量化交易平台大全
    Doctor of Philosophy in Computational and Mathematical Engineering
    Institute for Computational and Mathematical Engineering
    Requirements for the Master of Science in Computational and Mathematical Engineering
    MSc in Mathematical and Computational Finance
    万字长文:详解多智能体强化学习的基础和应用
    数据处理思想和程序架构: 使用Mbedtls包中的SSL,和服务器进行网络加密通信
    31-STM32+W5500+AIR202/302基本控制篇-功能优化-W5500移植mbedtls库以SSL方式连接MQTT服务器(单向忽略认证)
  • 原文地址:https://www.cnblogs.com/FallDream/p/cf398.html
Copyright © 2011-2022 走看看