bzoj 2802: [Poi2012]Warehouse Store 题解

【原题】

2802: [Poi2012]Warehouse Store

Time Limit: 10 Sec  Memory Limit: 64 MBSec  Special Judge

Submit: 94  Solved: 54

Description

有一家专卖一种商品的店,考虑连续的n天。

第i天上午会进货Ai件商品,中午的时候会有顾客需要购买Bi件商品,可以选择满足顾客的要求,或是无视掉他。

如果要满足顾客的需求,就必须要有足够的库存。问最多能够满足多少个顾客的需求。

Input

第一行一个正整数n (n<=250,000)。

第二行n个整数A1,A2,...An (0<=Ai<=10^9)。

第三行n个整数B1,B2,...Bn (0<=Bi<=10^9)。

Output

第一行一个正整数k,表示最多能满足k个顾客的需求。

第二行k个依次递增的正整数X1,X2,...,Xk,表示在第X1,X2,...,Xk天分别满足顾客的需求。

Sample Input

6

2 2 1 2 1 0

1 2 2 3 4 4

Sample Output

3

1 2 4

【分析】这道题我被坑的好久。

首先这肯定是贪心。我开始是这样想的:我们把顾客要求的多少排序,然后每次看看第I个顾客是否能给他,如果能的话就卖给他并更新我目前的钱。如果用f[i]表示到第i天剩余的钱的话,如果第K天的东西我卖了,我会把K+1~N的所有f元素都减去第K天顾客的要求数量。HHD表示应该减去1--K-1的f值。我们马上码好发现WA了。

【初始代码(开始用树状数组,后来怕写萎了,改成线段树了)】

#include<cstdio>
#include<algorithm>
#define L(x) (x&-x)
#define N 250005
using namespace std;
typedef long long ll;
ll f[N],data[N],write[N],temp,x,y,jia,n,i,ans,sum;
struct arr{ll x,id;}b[N];
struct arr2{ll l,r,sum,add;}a[N*4];
char opt[5];
inline void build(ll k,ll l,ll r)
{
  a[k].add=0ll;a[k].l=l;a[k].r=r;
  if (l==r) {a[k].sum=data[l];return;}
  ll mid=(l+r)>>1;
  build(k<<1,l,mid);build((k<<1)+1,mid+1,r);
  a[k].sum=a[k<<1].sum+a[(k<<1)+1].sum;
}
inline void down(ll k)
{
  if (a[k].add==0) return;
  a[k<<1].sum+=a[k].add*(a[k<<1].r-a[k<<1].l+1ll);
  a[(k<<1)+1].sum+=a[k].add*(a[(k<<1)+1].r-a[(k<<1)+1].l+1ll);
  a[k<<1].add+=a[k].add;a[(k<<1)+1].add+=a[k].add;
  a[k].add=0;
}
void update(ll k)
{
  if (a[k].l>=x&&a[k].r<=y)
  {
    a[k].sum+=jia*1ll*(a[k].r-a[k].l+1ll);
    a[k].add+=jia;return;
  }
  down(k);
  ll mid=(a[k].l+a[k].r)>>1;
  if (x<=mid) update(k<<1);
  if (y>mid) update((k<<1)+1);
  a[k].sum=a[k<<1].sum+a[(k<<1)+1].sum;
}
ll ask(ll k)
{
  if (a[k].l>=x&&a[k].r<=y) return a[k].sum;
  down(k);
  ll mid=(a[k].l+a[k].r)>>1;ll o=0;
  if (x<=mid) o+=ask(k<<1);
  if (y>mid) o+=ask((k<<1)+1);
  a[k].sum=a[k<<1].sum+a[(k<<1)+1].sum;
  return o;
}
inline ll Read()
{
  char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar());
  ll x=0;for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10ll+ch-'0';
  return x;
}
//inline void add(ll x,ll v){if (!x) return;for (;x<=n;x+=L(x)) f[x]+=v;}
//inline ll ask(ll x){ll s=0;for (;x;x-=L(x)) s+=f[x];return s;}
inline bool cmp(arr a,arr b){return a.x<b.x;}
int main()
{
  n=Read();
  for (i=1;i<=n;i++) x=Read(),data[i]=data[i-1]+x;
  build(1,1,n);
  for (i=1;i<=n;i++) b[i].x=Read(),b[i].id=i;
  sort(b+1,b+n+1,cmp);
  for (i=1;i<=n;i++)
  {
    x=y=i;temp=ask(1);
    if (temp>=b[i].x) x=i,y=n,jia=-b[i].x,update(1),write[++ans]=b[i].id;
  }
  sort(write+1,write+ans+1);
  printf("%lld\n",ans);
  for (i=1;i<=ans;i++) printf("%lld ",write[i]);
  return 0;
}

原来这样的更新是有问题的,无论是前面还是后面减,都有严重的类似后效性的东西。

经过SYC大神的指导,有一种完美的解决方案:从第一天开始每次判断当前的东西可不可以卖。如果可卖就卖掉并压入堆。如果卖不掉(缺货),去之前的堆中找最大值比较一下并决定是否卖。

【AC代码】

#include<cstdio>
#include<algorithm>
#include<queue>
#define N 250005
using namespace std;
typedef long long ll;
typedef pair<ll,ll>Pair;
Pair temp;
priority_queue<Pair>q;
inline ll Read()
{
  char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar());
  ll x=0;for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
  return x;
}
ll a[N],b[N],ans[N],now,n,i,big,id,cnt;
int main()
{
  n=Read();
  for (i=1;i<=n;i++) a[i]=Read();
  for (i=1;i<=n;i++) b[i]=Read();
  for (i=1;i<=n;i++)
  {
    now+=a[i];
    if (now>=b[i]) now-=b[i],q.push(make_pair(b[i],i)),ans[i]=1;
    else if (!q.empty())
    {
      temp=q.top();big=temp.first;id=temp.second;
      if (big>b[i]) q.pop(),ans[id]=0,now+=(big-b[i]),q.push(make_pair(b[i],i)),ans[i]=1;
    }
  }
  for (i=1;i<=n;i++) if (ans[i]) cnt++;
  printf("%lld\n",cnt);
  for (i=1;i<=n;i++) if (ans[i]) printf("%d ",i);
  return 0;
}

bzoj 2802: [Poi2012]Warehouse Store 题解

时间: 2024-10-02 15:29:59

bzoj 2802: [Poi2012]Warehouse Store 题解的相关文章

BZOJ 2802 Poi2012 Warehouse Store 堆+贪心

题目大意:有n天,早上进货中午卖,可以选择卖或者不卖,问最多可以卖出多少人 首先贪心的思想是如果当前能卖就卖 但是这样不一定是最优的 比如说我第一天来一个人把所有的库存都买走了 然后后面基本没有补给 后面的人都饿死了 因此我们维护一个大根堆来记录我们都卖出了多少份 如果有一个人买不到 我们去大根堆里寻找有没有买的比他多的 如果有 把之前的人取消 卖给这个人 这样虽然不能增加答案 但是可以增加库存 #include <cstdio> #include <cstring> #inclu

【BZOJ】2802: [Poi2012]Warehouse Store(贪心)

http://www.lydsy.com/JudgeOnline/problem.php?id=2802 自己yy了一下... 每一次如果够那么就买. 如果不够,考虑之前买过的,如果之前买过的比当前花费的钱多,那么就去掉之前买的,变成买现在的. 如何证明?不知道QAQ 还有...注意开longlong... #include <cstdio> #include <cstring> #include <cmath> #include <string> #inc

BZOJ2802 [Poi2012]Warehouse Store

恩...贪心来着... 我们先贪心当天能不能满足客户要求,如果能就尽量满足. 好了现在不能满足怎么办?作为一个无良的商家,可以退掉以前的订单...(现实中真的可以?...) 为了让当前剩余货物总量尽可能大,当然是退掉之前要求最高的订单喽,于是用堆维护一下就好了 注意long long什么的就好了 1 /************************************************************** 2 Problem: 2802 3 User: rausen 4 La

bzoj 2109 &amp; 2535 航空管制 题解

[] [分析]真的是一道贪心好题.开始我以为是一道大水题.建立拓扑图后(没环就是方便!),直接把最外层设定序号为1,第二层为2,bfs下去即可...结果发现:飞行序号不能相同...于是开始想. 先考虑第一个问题:打印一个合法序列.我开始是这么想的: 观察每个飞机的最晚飞行序号Ki,因为必定有解,所以我们可以让它的序号就是Ki.然后用它的时间去更新前面的时间(图可以反向建立).应该可以维护一个大根堆,每次挑出最大的一个进行处理. [简易代码] memset(T,0x7f,sizeof(T)); f

bzoj 1858: [Scoi2010] 序列操作 题解

[原题] 1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 1031  Solved: 529 [Submit][Status] Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区间内

矩阵乘法专题3——bzoj 1898 [Zjoi2004]Swamp 沼泽鳄鱼 题解

[原题] 1898: [Zjoi2004]Swamp 沼泽鳄鱼 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 425  Solved: 256 [Submit][Status] Description 潘塔纳尔沼泽地号称世界上最大的一块湿地,它地位于巴西中部马托格罗索州的南部地区.每当雨季来临,这里碧波荡漾.生机盎然,引来不少游客.为了让游玩更有情趣,人们在池塘的中央建设了几座石墩和石桥,每座石桥连接着两座石墩,且每两座石墩之间至多只有一座石桥.这

矩阵乘法专题4——bzoj 2326 [HNOI2011] 数学作业 题解

转载请注明:http://blog.csdn.net/jiangshibiao/article/details/24963747 [原题] 2326: [HNOI2011]数学作业 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 853  Solved: 473 [Submit][Status] Description [分析]我们按数字的位数来划分.对于K位数,我们就可以专门设计一个矩阵来计算. 然后就是注意细节了. [代码] #include

bzoj 3519: [Zjoi2014] 消棋子 题解

[序言]在大家怀疑的眼光下,我做了一个中午和半个下午.调了一个晚上的题目总算A了! [原题] 消棋子是一个有趣的游戏.游戏在一个r * c的棋盘上进行.棋盘的每个格 子,要么是空,要么是一种颜色的棋子.同一种颜色的棋子恰好有两个.每一轮, 玩家可以选择一个空格子(x, y),并选择上下左右四个方向中的两个方向,如果 在这两个方向上均存在有棋子的格子,而且沿着这两个方向上第一个遇到的棋子 颜色相同,那么,我们将这两个棋子拿走,并称之为合法的操作.否则称这个操 作不合法,游戏不会处理这个操作.游戏的

bzoj 3528 [ZJOI2014] 星系调查 题解

[原题] 星系调查 [问题描述] 银河历59451年,在银河系有许许多多已被人类殖民的星系.如果想要在行 星系间往来,大家一般使用连接两个行星系的跳跃星门.  一个跳跃星门可以把 物质在它所连接的两个行星系中互相传送. 露露.花花和萱萱被银河系星际联盟调查局任命调查商业巨擘ZeusLeague+ 的不正当商业行为. 在银河系有N个已被ZeusLeague+成功打入市场的行星系,不妨标号为 1,2,...,N.而ZeusLeague+在这N个行星系之间还拥有自己的M个跳跃星门.使 用这些跳跃星门,