Codeforces Round #444 (Div. 2)-贪心&尺取-Ratings and Reality Shows

39 篇文章 0 订阅
12 篇文章 0 订阅

http://codeforces.com/contest/887/problem/D
一个模特有两种活动。
① 拍照片,挣钱 a。 ②开演唱会,花费b
给定模特这两种工作的时间表。
模特可以选定一个时间举办一个座谈会,那么他拍照片的钱变c。开演唱会会花费d。
要求再模特座谈会之前和后len天 都不能赔钱。 要求你输出最小的座谈会天数。 没有输出-1.。
思路:枚举第i天作为 开始的茶话会的时间(茶话会是可以和当天其他的活动撞的,并且当天有影响),然后计算后len天是否有负数。
T了。
正确的写法类似尺取,维护正常天数的前缀和,再计算以i活动为初始,(i活动已经被影响了,因为要尽可能的早,所以时间再第i-
1个活动的 下一天就举办茶话会),长度问len的特殊天数的茶话会。
这里写图片描述
绿色部分是 茶话会举办的时间,i为第一个被影响的天数。红色部分为len。cf上很多的代码算的影响天数都是从i开始的,我深感不解
是某个大佬的证明?还是数据没有卡掉?

#include <bits/stdc++.h>
using namespace std;
/* 本来想写一个初级想法 超时一下再改的。
结果初级想法wa了一天。。
要类似尺取一样,
这道题有以下方向我没考虑到。
那就是 ① 举办talkshow的时间是马上的,可以和其他时间重合
② 如果以i为开始的话,那么开始talkshow的时间最短可以是 node[i-1]+1。
③ 如果以i为开头计算,如果不可行,再继续从i+1计算的话,着tm肯定不可行。
这tm就和匹配字符串一样,复杂度几乎是 n2
.最好的方法就是双指针维护 前缀和(小名叫尺取)。
方法。当i为开头的时候,维护一个前缀和。
   当不可以的时候,减去 首部分的前缀和(在这道题中是替换cd为ab)
*/
typedef long long ll;
const int maxn=3e5;
struct{
   ll kin,cos;
}node[maxn];
int n;
ll a,b,c,d,lim,sta;
int main()
{   while(~scanf("%d%lld%lld%lld%lld%lld%lld",&n,&a,&b,&c,&d,&sta,&lim)){
          for(int i=0;i<n;i++){
              scanf("%lld%d",&node[i].cos,&node[i].kin);
          }
          ll mn=1e17;
          ll ans=sta;
          ll sum2=0;
          int now=0;
          bool flag=false;
          int kk;
          for(int i=0;i<n;i++){
              ll tt;
              if(i==0)tt=0;
              else tt=node[i-1].cos+1;//计算i活动第一个被影响时,茶话会开始的日期
              while(now<n&&(node[now].cos-tt)<lim){
                  if(node[now].kin==0)
                      sum2-=d;
                  else
                      sum2+=c;
                  mn=min(sum2,mn);
                 now++;
              }
              if(mn+ans>=0){
                 flag=true;
                 kk=i;
                 if(kk==0)
            printf("0\n");
          else
            printf("%lld\n",node[kk-1].cos+1);
            break;              }
              if(node[i].kin==1){
                 mn-=c;
                 sum2-=c;
                 ans+=a;
              }
              else {
                 mn+=d;
                 sum2+=d;
                 ans-=b;
              }
              if(ans<0){
                puts("-1");
                flag=true;
                break;
              }
          }
          if(!flag)
          printf("%lld\n",node[n-1].cos+1);



    }


    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值