zoukankan      html  css  js  c++  java
  • 【CF500F】New Year Shopping

    题目

    题目链接:https://codeforces.com/contest/500/problem/F
    \(n\) 种商品,第 \(i\) 种商品的价格是 \(c_i\) ,购买后可以增加 \(h_i\) 的快乐指数,将于第 \(t_i\) 天上市。商品的保质期为 \(p\) 天,过期后不能再购买,即第 \(i\) 种商品只能在第 \(t_i\) 天到第 \(t_i+p-1\) 天之间购买,每种商品只能购买一次。
    \(q\) 个询问,每次给定两个整数 \(a,b\) ,求在第 \(a\) 天去购物,最多使用 \(b\) 元的情况下可以得到的最大快乐指数。询问之间互不干扰。
    \(n\leq 3\times 10^4\)\(q\leq 2\times 10^4\),所有价格 \(\leq 3\times 10^4\),所有时间和快乐指数 \(\leq 2\times 10^4\)

    思路

    这道题似乎有很多做法,但是我只能想到卑微的 \(O(nq\log n)\)
    因为所有物品持续的时间都是一样的,所以按照上架时间排序后,每次的询问就是把一段区间的物品拿出来做 01 背包。
    也就是需要维护一个队列,然后在某一时刻查询队列内所有物品的 01 背包。
    而一个队列可以用两个栈 \(s1,s2\) 来实现:插入物品就往 \(s2\) 插入;删除物品就在 \(s1\) 删除;当 \(s1\) 为空时,就把 \(s2\) 所有元素依次弹出插入 \(s1\)
    然后维护两个栈中每一个元素到栈底的背包。按照时间离线询问,然后只需要合并一下两个栈栈顶的背包即可。
    时间复杂度 \(O(nq)\)
    实现上不需要真的开栈,维护区间 \([l,mid]\) 为第一个栈的元素,\([mid+1,r]\) 为第二个栈的元素即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=4010,M=20010;
    int n,p,Q,l,r,mid,f[N][N],ans[M];
    
    struct node1
    {
    	int w,v,t;
    }a[N];
    
    struct node2
    {
    	int m,t,id;
    }b[M];
    
    bool cmp1(node1 x,node1 y)
    {
    	return x.t<y.t;
    }
    
    bool cmp2(node2 x,node2 y)
    {
    	return x.t<y.t;
    }
    
    void insert(int x,int *g,int *h)
    {
    	memcpy(g,h,sizeof(f[0]));
    	for (int i=4000;i>=a[x].w;i--)
    		g[i]=max(g[i],g[i-a[x].w]+a[x].v);
    }
    
    int main()
    {
    	scanf("%d%d",&n,&p);
    	for (int i=1;i<=n;i++)
    		scanf("%d%d%d",&a[i].w,&a[i].v,&a[i].t);
    	scanf("%d",&Q);
    	for (int i=1;i<=Q;i++)
    	{
    		scanf("%d%d",&b[i].t,&b[i].m);
    		b[i].id=i;
    	}
    	sort(a+1,a+1+n,cmp1);
    	sort(b+1,b+1+Q,cmp2);
    	l=1; mid=r=0;
    	for (int t=1,i=1;t<=20000;t++)
    	{
    		for (;r<n && a[r+1].t==t;r++)
    			insert(r+1,f[r+1],f[(r==mid)?0:r]);
    		while (l<=mid && a[l].t+p==t) l++;
    		if (l>mid)
    		{
    			mid=r;
    			for (int j=mid;j>=l;j--)
    				insert(j,f[j],f[(j==mid)?0:j+1]);
    		}
    		for (;i<=Q && b[i].t==t;i++)
    			for (int j=0;j<=b[i].m;j++)
    			{
    				int res1=(l<=mid) ? f[l][j] : 0;
    				int res2=(mid<r) ? f[r][b[i].m-j] : 0;
    				ans[b[i].id]=max(ans[b[i].id],res1+res2);
    			}
    	}
    	for (int i=1;i<=Q;i++)
    		printf("%d\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    使用Koa搭建一个mock服务器
    d3 使用记录: 树形图
    转载: 矩阵的运算及运算规则
    d3 使用记录: 插值
    d3 使用记录: Selection
    转载: javascript 模块化历程
    Git 常用操作
    贝塞尔曲线_初探
    css 基础-
    Freemarker模板语法
  • 原文地址:https://www.cnblogs.com/stoorz/p/15758574.html
Copyright © 2011-2022 走看看