1 条题解
-
0
简要题意
给若干物品,按一定顺序选取物品。每个物品有一个限制值:如果当前选取物品的体积没有超过该值,则物品的体积乘上一个定值。询问最大可能总体积。
分析
首先,我们可以把任务分为 “好任务”(可以获得倍增器的任务)和 “普通任务”(不能获得倍增器的任务)。
那么我们观察到:一定存在一个任务顺序,使得我们先做好任务,再做普通任务。
证明:如果存在一个两个任务 ,且 是普通任务, 是好任务,且 先于 做,我们设当前经验为 。那么有 ;如果我们交换 和 的顺序,那么有 。两个任务性质不变,因此交换不会变劣。
其次,我们再观察到:普通任务的顺序不影响最后经验值。
因为顺序只关系我们能否获得增幅器,既然已经不能获得增幅器了,那么顺序也就没有意义了。
最后,我们有一个惊人注意力:我们定义 ,即做完任务 时可能的最大经验值,那么我们会优先做 小的好任务。
证明:
我们假设存在两个好任务 , 先于 做且 ,那么可以推断:
$$\begin{cases} xp \le xd_i-1\\ xp+cx_i \le vd_j-1\\ xp \le vd_j-1\\ vd_j+cx_j-1\le vd_i+cx_i-1 \end{cases}$$那么我们要判断 和 的大小关系,注意到:
$$vd_i-1 \ge vd_j+cx_j-cx_i\ge xp+cx_i+cx_j-cx_i+1 \ge xp+cx_j$$因此交换 和 的顺序不会改变任务的性质,不会使答案变劣。
根据上述性质,我们按照 给任务升序排序,那么依照这个顺序 dp 即可。
这个 dp 类似于背包,我们定义 为考虑到第 个物品,是否可以使从任务获得的经验为 。转移时钦定当前物品是否在好物品集合中,这是简单的。找答案就倒序枚举 dp 数组,找到一个可以的经验值。
我们定义 时间复杂度为 ,接近 ,非常不可过。
考虑优化:
- 我们可以把好任务获得的经验分成 和 ,这样我们就可以只统计后面那部分的贡献。换句话说,我们可以只关心好任务的选取情况;
- 因为所有好任务提供的经验的都有 的系数,将其提出,可以降低值域大小;
- 背包可以使用
bitset优化;
经过上述优化后,我们定义 ,时间复杂度为 。
代码
#include<bits/stdc++.h> #define inf 0x3f3f3f3f #define Inf (1ll<<60) #define For(i,s,t) for(int i=s;i<=t;++i) #define Down(i,s,t) for(int i=s;i>=t;--i) #define ls (i<<1) #define rs (i<<1|1) #define bmod(x) ((x)>=p?(x)-p:(x)) #define lowbit(x) ((x)&(-(x))) #define End {printf("NO\n");exit(0);} using namespace std; typedef long long ll; typedef pair<int,int> pii; inline void ckmx(int &x,int y){x=(x>y)?x:y;} inline void ckmn(int &x,int y){x=(x<y)?x:y;} inline void ckmx(ll &x,ll y){x=(x>y)?x:y;} inline void ckmn(ll &x,ll y){x=(x<y)?x:y;} inline int min(int x,int y){return x<y?x:y;} inline int max(int x,int y){return x>y?x:y;} inline ll min(ll x,ll y){return x<y?x:y;} inline ll max(ll x,ll y){return x>y?x:y;} char buf[1<<20],*p1,*p2; #define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++) #define read() ({\ int x = 0, f = 1;\ char c = gc();\ while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = gc();\ while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc();\ f * x;\ }) void write(int x){ if(x>=10) write(x/10); putchar(x%10+'0'); } const int N=2005,M=4e6+4; int n,v,c,m=4e6+4; struct Node{int x,d,mx,id;}a[N]; bool cmp(Node x,Node y){return x.mx<y.mx;} bitset<M> f,large,g; int main() { n=read(),v=read(),c=read(); For(i,1,n){ a[i].x=read(),a[i].d=read(); a[i].mx=c*a[i].x+v*a[i].d-1,a[i].id=i; } sort(a+1,a+n+1,cmp); f.set(0),large.set(0); int pw=1; while(pw<m) large|=(large<<pw),pw<<=1; int num=0,lim; For(i,1,n){ num+=a[i].x,lim=min(num,(a[i].d*v-1)/c); g=(large>>(m-lim-1)); g=(f&g); g=(g<<a[i].x); f=(f|g); } Down(i,num,0) if(f[i]){ ll val=1ll*(c-1)*i+num; printf("%lld",val); break; } return 0; }
- 1
信息
- ID
- 8530
- 时间
- 10000ms
- 内存
- 2048MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者