zoukankan      html  css  js  c++  java
  • 【Codeforces Round #437 (Div. 2) C】 Ordering Pizza

    【链接】h在这里写链接


    【题意】


        给你参赛者的数量以及一个整数S表示每块披萨的片数。
        每个参数者有3个参数,si,ai,bi;
        表示第i个参赛者它要吃的披萨的片数,以及吃一片第一种披萨增加的幸福感,
        以及吃一片第二种披萨增加的幸福感。

        两种披萨都能任意数量地订购。
        但是总数num有一个上限。
        就是S*num>=∑si
        且num最小。
        也就是说相当于给你一个num;
        让你求两种披萨各要买多少个a,b(a+b==num)。
        使得参赛者的幸福感尽可能高。
        (参赛者即可以选择第一种、也可以同时吃第二种)


    【题解】


        如果每个人想要的披萨片数和<=S
        那么只能买一块披萨。
        则买a或买b,那么每个人都只能选A或选B
        取较大值就好。

        矛盾点在哪里?
            虽然你的a大,但是已经没有A披萨给你了
            或者,全都买B披萨更合适

        枚举最后买了多少个B披萨
        i=0
        则一开始全都吃A披萨
        i=1
        则让B-A前S大的人变成吃B披萨
        i=2
        则让B-A前2S大的人变成吃B披萨
        在i=i-1的基础上改一下就好
            记录到了哪一个人,那个人还能有多少从A->B

        i最大为num,且i*S<=∑si

        以B-A为关键字降序排一下?


    【错的次数】


    0

    【反思】


    加注释的方式真的很好。。

    【代码】

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int N = 1e5;
    
    struct abc{
        ll a,b,rest,c;
    };
    
    int n;
    ll S,temp,num,srest,ans;
    abc a[N+10];
    
    bool cmp(abc a,abc b)
    {
        return a.c > b.c;
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        scanf("%d%lld",&n,&S);
        for (int i = 1;i <= n;i++){
            scanf("%lld%lld%lld",&a[i].rest,&a[i].a,&a[i].b);
            a[i].c = a[i].b-a[i].a;
            temp += a[i].rest*a[i].a;
            srest += a[i].rest;
        }
    
        //获取最多买多少个披萨
        ll l = 1,r = 1e10 + 100;
        while (l <= r)
        {
            ll mid = (l+r)>>1;
            ll temp = mid*S;
            if (temp >= srest)
            {
                num = mid;
                r = mid - 1;
            }else
                l = mid + 1;
        }
    
        sort(a+1,a+1+n,cmp);//按照B-A降序排
    
        ans = temp;//一开始全都吃A披萨
        //这个num的值可能会很大,你可能不能枚举出来全部。
        //在可以的情况下,尽量贪心选。只要B披萨的数目不超过num就可以了
        ll temp1 = 0,tnum = 0;//tnum是之前剩余的变成B更优的个数
        //temp1是那些变成B之后答案的递增值
    
        ll spe = num*S-srest;//多买的披萨的片数
        //S片才能凑够一个B披萨
    
        for (int i = 1;i <= n;i++)
        {
            //第i个人有一些变成选B披萨
    
            if (a[i].c < 0)//这个人变成B之后答案会减小
            {//用spe尽量不让他减小->本来肯定要有一些人从a变成B,现在可以用多余的填,不用让他们变了
                //前提是
                if (tnum + a[i].rest + spe >= S)//够凑了
                {
                    ll dd = tnum + spe;
                    if (dd >= S)//不用加就能超过了
                    {
                        ans = max(ans,temp + temp1);
                    }else
                    {
                        ll js = S-dd;
                        ans = max(ans,temp + temp1 + a[i].c*js);
                    }
                    temp1 = 0;
                    break;
                }
            }
            if (tnum + a[i].rest < S)//如果没有超过了1块披萨的量
            {
                temp1 += a[i].rest*a[i].c;
                tnum += a[i].rest;
            }else//超过了
            {
                //这一个人的a->b选了多少个?
                temp += temp1;//优先加之前的
    
                ll rr = (a[i].rest + tnum)%S;//剩余的
                ll choose = a[i].rest-rr;//之后再加当前的
                temp += choose*a[i].c;
    
                tnum = rr;//前些轮的剩余变成rr了
                temp1 = rr*a[i].c;//temp1变成rr*a[i].c了
    
                ans = max(ans,temp);//取最大值
                //显然这个过程中B是肯定够用的
            }
        }
        //temp1 = 1;
        //printf("%lld
    ",temp1);
        if (tnum + spe >= S)//全为正数最后一个剩下的可能还可以和多余的凑出来一个S
        {
            ans = max(ans,temp + temp1);
        }
    
        printf("%lld
    ",ans);
        return 0;
    }
    


  • 相关阅读:
    input 只能输入数字
    “学生宿舍管理系统”主要内容及特点
    web_03Java ee实现定时跳转,使用C3P0,DBUtils类重构数据库操作
    DBUtils工具类的使用
    C3P0连接池
    java ee 中 Jsp 页面的定时的跳转(数字倒数)
    JSP中实现网页访问统计的方法【转】
    Java web验证码
    web_02Java ee实现验证码,网站访问次数功能
    web_01Java ee实现登陆注册功能
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7625976.html
Copyright © 2011-2022 走看看