【loli的胡策】NOIP训练7.18(乱搞+背包dp+并查集分治)
来源:互联网 发布:美国海关数据库 编辑:程序博客网 时间:2024/04/27 23:10
T2题目:
Time limit: 1seconds
Memory limit: 128 megabytes
在比特镇一共有 n 家商店,编号依次为 1 到 n。每家商店只会卖一种物品,其中第 i 家商店的物品单价为 ci,价值为 vi,且该商店开张的时间为 ti。Byteasar计划进行m次购
物,其中第i次购物的时间为Ti,预算为Mi。每次购物的时候,Byteasar会在每家商店购买最多一件物品,当然他也可以选择什么都不买。如果购物的时间早于商店开张的时间,
那么显然他无法在这家商店进行购物。现在 Byteasar 想知道,对于每个计划,他最多能购入总价值多少的物品。请写一个程序,帮助Byteasar 合理安排购物计划。
注意:每次所花金额不得超过预算,预算也不一定要花完,同时预算不能留给其它计划使用。
Input
第一行包含两个正整数 n;m,表示商店的总数和计划购物的次数。
接下来 n 行,每行三个正整数 ci; vi; ti,分别表示每家商店的单价、价值以及开张时间。
接下来 m 行,每行两个正整数 Ti;Mi,分别表示每个购物计划的时间和预算。
Output
输出 m 行,每行一个整数,对于每个计划输出最大可能的价值和。
Examples
market.in
5 2
5 5 4
1 3 1
3 4 3
6 2 2
4 3 2
3 8
5 9
market.out
10
12
第一个计划可以在商店 2,3,5 各购买一件物品,总花费为 1 + 3 + 4 = 8,总价值为 3 + 4 + 3 = 10。
第二个计划可以在商店 1,2,3 各购买一件物品,总花费为 5 + 1 + 3 = 9,总价值为 5 + 3 + 4 = 12。
题解:
背包dp
这道题n 很小,m 很大,如果直接做m次背包的话一定会TLE.(60分)
所以我们考虑消除掉影响,讲物品按时间从小到大排序,再将询问按照中止位置排序(就是当前询问所能买到的最后一物品的编号),这样子顺着扫就能消除时间的影响,只要
当中止位置=当前物品的时候更新答案即可,消除掉了时间的影响。
那么M是10^9,这个肯定不能作为数组的一维表示,我们考虑转化一下,将sumv作为一维,进行背包,f[i]表示价值为i的最小单价和,然后统计答案的时候从后往前扫,扫到的
第一个满足f[i]<=b[t].c的i就是当前询问的答案。
但是如果对于每个询问都倒着扫一遍,太耗时了。我们发现n很小这就非常好了,我们能否将中止位置相同的一遍扫出来呢?可以的在排序的时候以中止位置为第一关键字(从
小到大),预算为第二关键字(从大到小),这样的话排在后面的预算小,如果预算大的都可以满足,预算小的也可以满足。于是只要中止位置相同就可以一遍扫下来。
时间复杂度为O(N^3+NM)
代码:
#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#define LL long longusing namespace std;int ans[100005],n;LL f[305*305];struct dian{int c,v,t,pos;}shop[305],ren[100005];int cmp(dian a,dian b){return a.t<b.t;}int cmp1(dian a,dian b){return (a.pos<b.pos) || (a.pos==b.pos&&a.v>b.v);//前面的时间小预算大 }int erfen(int x)//找到询问所能买到最后一物品的编号 {int ans=0;int l=1,r=n,mid;while (l<=r){mid=(l+r)>>1;if (shop[mid].t<=x) ans=mid,l=mid+1;else r=mid-1; }return ans;}int main(){freopen("market.in","r",stdin);freopen("market.out","w",stdout);int m,i,j,k,sum=0;scanf("%d%d",&n,&m);for (i=1;i<=n;i++){scanf("%d%d%d",&shop[i].c,&shop[i].v,&shop[i].t); sum+=shop[i].v;}sort(shop+1,shop+n+1,cmp);for (i=1;i<=m;i++) {scanf("%d%d",&ren[i].t,&ren[i].v);ren[i].c=i; ren[i].pos=erfen(ren[i].t); } sort(ren+1,ren+m+1,cmp1);memset(f,0x7f,sizeof(f));f[0]=0;int to=1;while (!ren[to].pos && to<=m) to++;for (i=1;i<=n;i++){ for (k=sum;k>=shop[i].v;k--)//f[i]表示价值为i的最小单价 f[k]=min(f[k],f[k-shop[i].v]+(LL)shop[i].c); int last=sum; while (ren[to].pos==i && to<=m)//因为to有<m的条件,所以这个条件一个ans只能进一次,所以前面的商铺一定要达到最好状态,所以需要二分找到一个合适的位置 {for (j=last;j>=1;j--) if (f[j]<=ren[to].v) { ans[ren[to].c]=j; last=j; break; } to++; } if (to>m) break;}for (i=1;i<=m;i++) printf("%d\n",ans[i]); }
- 【loli的胡策】NOIP训练7.18(乱搞+背包dp+并查集分治)
- 【loli的胡策】NOIP训练7.17(模拟+乱搞二进制+乱搞BFS)
- 【loli的胡策】NOIP训练8.12(二分?+dp?)
- 【loli的胡策】NOIP训练7.15(签到+dp+线段树)
- 【loli的胡策】NOIP训练8.10(数论+树形dp+贪心)
- 【loli的胡策】NOIP训练10.2(快速幂+树形期望dp)
- 【loli的胡策】联校11.2(dp+乱搞+期望dp)
- 【loli的胡策】NOIP训练7.20(二分+主席树)
- 【loli的胡策】NOIP训练8.15(找规律+暴力)
- 【loli的胡策】NOIP训练10.5(组合数学+catalan数讲解)
- 【loli的胡策】联校11.1(乱搞)
- 【loli的胡策】高一信心场11.2(bitset+dp+二分+树形背包)
- 【loli的胡策】联校10.26(抖动dp+树形dp*期望)
- 分组背包dp+并查集 vijos1250
- Codevs_P3372 选学霸(并查集+DP+背包)
- 【yveh的胡策】训练8.24(乱搞)
- noip 并查集
- NOIP模拟题 2016.10.31 [DP] [搜索] [并查集]
- 2017 年学习的编程语言、框架和工具
- Google 开源技术protobuf
- linux系统下搭建Apache+JK+Tomcat集群
- angular js 中异步加载
- Ubuntu 14.04 ,安装jdk
- 【loli的胡策】NOIP训练7.18(乱搞+背包dp+并查集分治)
- Merge into 详细介绍
- android app 三星s8 适配问题 和 meta-data 动态修改
- 如何在Eclipse下安装SVN插件——subclipse
- 数学之路(2)-数据分析-R基础(2)
- 使用Eclipse编译运行MapReduce程序 Hadoop2.7.3
- 电影票(水题 杭电排位赛-6)
- 旋转标签
- vue todo-mvc