我是题面

恩,贪心,鉴定完毕。

一个物品是否放进来,取决于它是否能对答案做出贡献。

那物品i的贡献就是\(w[i]-r[i]\)

可是收益的减少是会叠加的

那就是\(w[i]-j*r[i]\),j表示选择物品i后又选择的物品数量

可是我怎么知道选择i后又会选择几件物品啊

那么我们引入一个新的值\(d[i]=w[i]/r[i]\),表示若使物品i对答案有贡献,选择物品i后最多再选择d件物品

既然这样,我们也有点眉目了,dfs啊

很好,写的很漂亮,50。。。TLE

dfs

看来是不能再优化了

那让我们退回去,往前看“可是我怎么知道选择i后又会选择几种物品啊”

好像有一种方法可以知道还会再选几件,没错,你是不是也想到了,就是 dfs 动规

我们用\(f[i][j]\)表示在前i种物品中选择j件,可是这怎么记忆之前所说的j呢?

还记得之前说好的贪心吗,这里继续贪。

我们把物品按照r从大到小的顺序排序,\(f[i][j]\)表示i件物品选择j件且最先选择j件时的收益

这里的贪心很好证明,既然r要取多次,那么我们自然默认让更小的r选择更多的次数

下面是代码

dfs版

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc() getchar()
#define maxn 3005
using namespace std; inline ll read(){
ll a=0;int f=0;char p=gc();
while(!isdigit(p)){f|=p=='-';p=gc();}
while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
return f?-a:a;
}
void write(ll a){
if(a>9)write(a/10);
putchar(a%10+'0');
}
int n; struct ahaha{
int w,r,d;
friend bool operator < (ahaha x,ahaha y){
return x.d>y.d;
}
}a[maxn]; bool c[maxn]; //表示物品是否被选择过
int ans;
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
void dfs(int sum,int sr,int sy){ //sum表示当前收益,sr表示需要累计下去的r,sy表示最多还能选择sy个数贪心就不优了
ans=max(ans,sum); //因为不知道选多少个数,所以ans每步比较
if(!sy)return; //如果不能再选 返回
for(int i=1;i<=n;++i){
if(c[i])continue;
c[i]=1;
dfs(sum+a[i].w-sr,sr+a[i].r,min(sy-1,a[i].d)); //sy应取最小值
c[i]=0;
}
} inline void solve(){
for(int i=1;i<=n;++i){
c[i]=1;
dfs(a[i].w,a[i].r,a[i].d);
c[i]=0;
}
} int main(){
n=read();
for(int i=1;i<=n;++i)a[i].w=read(),a[i].r=read(),a[i].d=a[i].w/a[i].r;
sort(a+1,a+n+1);
solve();
write(ans);
return 0;
}

DP版

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc() getchar()
#define maxn 3005
using namespace std; inline ll read(){
ll a=0;int f=0;char p=gc();
while(!isdigit(p)){f|=p=='-';p=gc();}
while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
return f?-a:a;
}
void write(ll a){
if(a>9)write(a/10);
putchar(a%10+'0');
}
int n,f[maxn][maxn],ans; struct ahaha{
int w,r;
friend bool operator < (ahaha x,ahaha y){
return x.r>y.r;
}
}a[maxn]; int main(){
n=read();
for(int i=1;i<=n;++i)a[i].w=read(),a[i].r=read();
sort(a+1,a+n+1);
f[1][1]=a[1].w;
for(int i=2;i<=n;++i)
for(int j=1;j<=i;++j)
f[i][j]=max(f[i-1][j],f[i-1][j-1]+a[i].w-a[i].r*(j-1)); //表示选择i个物品时,选择物品i和不选物品i两种操作
for(int i=1;i<=n;++i)ans=max(ans,f[n][i]);
write(ans);
return 0;
}

最新文章

  1. sql按字符截取字段
  2. sizzle分析记录:属性选择器
  3. 使用css3的动画模拟太阳系行星公转
  4. springfox.documentation.spi.DocumentationType配置示例
  5. HDU4865 Prince and Princess 强连通分量+二分图判定
  6. 数据结构练习 00-自测4. Have Fun with Numbers (20)
  7. flex4.6事件分派+组件+参数传递
  8. C#.Net前台线程与后台线程的区别
  9. jbpm部署流程定义到MySql报乱码解决方案
  10. JVM和java应用服务器调优
  11. jvm内存分配和回收策略
  12. 微信小程序中不同页面间的参数传递
  13. Java并发编程:synchronized和锁优化
  14. Java之增强的for 循环
  15. python传入不确定个数参数
  16. python基础知识10---算法
  17. [z]c++ 和 java 利用protobuf 通讯
  18. Mybatis的自动映射autoMappingBehavior与mapUnderscoreToCamelCase
  19. dede频道页实现三级栏目嵌套调用文章
  20. linux获取日志指定行数范围内的内容

热门文章

  1. [2016北京集训测试赛5]小Q与内存-[线段树的神秘操作]
  2. [BZOJ4011][HNOI2015]落忆枫音-[dp乱搞+拓扑排序]
  3. python 多线程笔记(1)-- 概念
  4. day 7 引用
  5. [转]理解Linux文件系统之inode
  6. protobuf工程的编译以及使用
  7. 使用Photon引擎进行unity网络游戏开发(四)——Photon引擎实现网络游戏逻辑
  8. PHP自定义生成二维码跳转地址
  9. EasyUI validatebox 自定义ajax验证用户名是否已存在
  10. PHPCMS如何让手机站点取消浏览大图直接加载原图