[BZOJ 2802]Poi2012 Warehouse Store

好坑的一道题目!

看到题面,再看看   “In tests worth 50% of the points the condition n<=1000 holds in addition.” ,  很容易把人往dp优化之类的地方想。

然后就会杯具了。。。。跳出dp吧!

把两个数列分别做个前缀和,任务很明显,在b数组中删除一些数,使得前缀和数组中每个i,sumai>=sumbi

注意到每次删除bi有影响的只有区间[i,n],由此我们可以贪心了。

从前向后扫描,如果此处还不满足sumai>=sumbi,只需在[1,i]中找到未被删除的最大的bj,删除,直到满足sumai>=sumbi

找最大值可以用对实现。注意到被删的数字最前缀和后不减,那么直接用变量表示被删了多少数  而不用线段树赋值。

具体实现见程序吧~~~~


#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int Maxn=300005;
LL a[Maxn],b[Maxn],suma[Maxn],sumb[Maxn],dt;
int i,n,ans,p[Maxn];
bool v[Maxn];
struct arr
{
  int x;
  bool operator <(const arr &a)const
    { return b[x]<b[a.x]; }
} tmp;
priority_queue <arr> heap;


int main(){
  freopen("hur.in","r",stdin);
  freopen("hur.out","w",stdout);
  scanf("%d",&n);
  for (i=1;i<=n;i++)
    scanf("%I64d",&a[i]);
  for (i=1;i<=n;i++)
    scanf("%I64d",&b[i]);
  for (i=1;i<=n;i++){
    suma[i]=suma[i-1]+a[i];
	sumb[i]=sumb[i-1]+b[i];
  }
  for (i=1,dt=0;i<=n;i++){
  	heap.push((arr){i});
  	while (sumb[i]-suma[i]>dt){
  	  tmp=heap.top();
  	  heap.pop();
  	  dt+=b[tmp.x];
  	  v[tmp.x]=1;
    }
  }
  for (i=1;i<=n;i++)
    if (!v[i]) p[++ans]=i;
  printf("%d\n",ans);
  if (ans==0) return 0;
  for (i=1;i<ans;i++)
    printf("%d ",p[i]);
  printf("%d\n",p[ans]);
  return 0;
}


你可能感兴趣的:(poi,heap,2012,贪心)