问题简述

给定\(n\)个盒子,每个盒子的容器为\(b[i]\),里面装有\(a[i]\)个物品。今有\(q\)组询问,每组询问给出一个正整数\(k(k<=n)\),已知一个盒子里的一件物品转移到另一个盒子需要一单位时间,要求将所有物品转移到任意\(k\)个箱子中最少需要多少时间。

数据范围

对于前60%的数据,\(n<=20\). \(q<=100\)

对于前100%的数据,\(n<=80\). \(q<=200\). \(a[i]<=b[i]<=20\)

看到这个题,我的第一反应就是暴力

暴力很好想,先把数组排个序,直接dfs查找前(n-k)个箱子中的物品进行验证就可以了

我们会发现\(n<=80\),但\(q<=200\),所以一定会有重复的问题

这时可以开个数组记录一下搜索,这样就把\(q\)从\(200\)变为\(80\)

这样你就获得了\(60\)分。。。

(其实还可以加上一些剪枝,比如如果搜的上一个盒子失败了,那这一个的盒子的容积必须小于上一个,否则就不行,但是并没有什么卵用

代码:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
int n;
int q;
struct node{
int a,b;
}box[85];
int ans[85];
int c[85];
int num;
int maxx;
int tot;
int totl;
int ccc;
bool cmp(node x,node y)
{
if(x.a==y.a) return x.b<y.b;
return x.a<y.a;
}
bool cmp2(int a,int b)
{
return a>b;
}
bool flag;
bool tag;
int s;
void dfs(int dep,int num,int now,int lor,int cap)
{
if(dep>=num)
{
if(totl<=tot-cap)
{
//cout<<lor<<" "<<tot-cap<<endl;
flag=1;
ans[num]=lor;
}else{
tag=1;
ccc=min(ccc,cap);
}
return;
}
for(int i=now+1;i<=n;i++)
{
if(flag==1) return;
if(cap+box[i].b<ccc)
{
if(tag==1) if(box[i].b>box[i-1].b) continue;
dfs(dep+1,num,i,lor+box[i].a,cap+box[i].b);
}
}
return;
}
int main(){
freopen("str.in","r",stdin);
freopen("str.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)
{
box[i].a=read();
totl+=box[i].a;
}
for(int i=1;i<=n;i++)
{
box[i].b=read();
tot+=box[i].b;
c[i]=box[i].b;
}
q=read();
memset(ans,0x3f,sizeof(ans));
sort(box+1,box+1+n,cmp);
sort(c+1,c+1+n,cmp2);
while(q--)
{
num=read();
if(ans[n-num]<=1600)
{
printf("%d\n",ans[n-num]);
continue;
}
if(num<=maxx)
{
ans[n-num]=-1;
puts("-1");
continue;
}
s=0;
for(int i=1;i<=num;i++)
{
s+=c[i];
}
if(s<totl)
{
maxx=max(maxx,num);
ans[n-num]=-1;
puts("-1");
continue;
}
flag=0;
tag=0;
ccc=INT_MAX;
dfs(0,n-num,0,0,0);
if(flag==1){
printf("%d\n",ans[n-num]);
}else{
ans[n-num]=-1;
puts("-1");
}
} return 0;
}

那么,正解是什么?

动态规划

仔细地观察题面,我们会发现转移时间只和盒子剩余的体积和选择货物的大小有关

这时我们可以设一个三维\(dp\)数组

\(dp[i][j][k]\)表示在前\(i\)个盒子里,选择了\(j\)个,剩余\(k\)体积的货物的最大值

对于第\(i\)个箱子有两种情况

1.不选择\(i\)号箱 \(dp[i][j][k]=dp[i-1][j][k]\)

2.选择\(i\)号箱 \(dp[i][j][k]=dp[i-1][j-1][v-(b[i]-a[i])]+a[i]\)

所以我们就得到了转移方程

\(f[i][j][v]=max(f[i-1][j][v], f[i-1][j-1][v-(b[i]-a[i])] + a[i])\)

对于询问\(k\)个箱子最小时间,只需要在\(f[n][j][k]\)跑一遍\(j\)和\(k\)判断当前空余体积\(k\)是否能容下剩余\((sum – f[n][j][k])\)个货物即可

代码:

#include<bits/stdc++.h>
using namespace std;
template <typename T>
void readin(T &x) {
x = 0;
T fh = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
x *= fh;
}
void d_read(double &x) {
x = 0.0;
int fh = 1;
char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = x * 10 + (ch ^ 48);
if (ch == '.') {
double num = 1.0;
ch = getchar();
for (; isdigit(ch); ch = getchar()) x = x + (num /= 10) * (ch ^ 48);
}
x *= fh;
} template <typename T>
void wt(T x) {
if (x > 9) wt(x / 10);
putchar(x % 10 + 48);
}
template <typename T>
void writeln(T x, char c) {
if (x < 0) {
putchar('-');
x = -x;
}
wt(x);
putchar(c);
}
int f[105][105][6055], n, a[105], b[105], ans[105], inf = 2100, lim = 2000;
int main() {
freopen("str.in","r",stdin);
freopen("str.out","w",stdout);
readin(n);
int flg = 0;
for (int i = 1; i <= n; i ++) {
readin(a[i]);
if (a[i]) flg ++;
}
for (int i = 1; i <= n; i ++) {
readin(b[i]);
}
for (int i = 0; i <= n; i ++) {
for (int j = 0; j <= n; j ++) {
for (int v = 0; v <= inf * 2; v ++) {
f[i][j][v] = -1e9;
}
}
}
f[0][0][0] = 0;
for (int i = 1; i <= n; i ++) {
for (int j = 0; j <= i; j ++) {
for (int v = 0; v <= lim; v ++) {
if (f[i - 1][j][v] != -1e9) f[i][j][v] = max(f[i][j][v], f[i - 1][j][v]);
if (j && v >= (b[i] - a[i]) && f[i - 1][j - 1][v - (b[i] - a[i])] != -1e9) f[i][j][v] = max(f[i][j][v], f[i - 1][j - 1][v - (b[i] - a[i])] + a[i]);
}
}
}
int sum = 0;
for (int i = 1; i <= n; i ++) {
sum += a[i];
}
for (int j = 1; j <= flg; j ++) {
ans[j] = 1e9;
for (int v = 0; v <= lim; v ++) {
if (sum - f[n][j][v] <= v) ans[j] = min(ans[j], sum - f[n][j][v]);
}
}
int q, k;
readin(q);
for (int i = 1; i <= q; i ++) {
readin(k);
if (ans[k] == 1e9) puts("-1");
else writeln(ans[k], '\n');
}
return 0;
}

但是,还有一个很大的问题……

就是题面到底和字符串有什么关系啊喂(

淘淘蓝蓝的CSP-S神妙膜你赛2-淘淘蓝蓝喜欢01串 题解的更多相关文章

  1. cdcqの省选膜你赛

    cdcqの省选膜你赛 比赛当天因为在杠hnoi2016的大数据结构没有参加,今天补了一下.挺好玩的虽然不看一句话题意的话真的卡读题 此生无悔入东方,来世愿生幻想乡 2651. 新史「新幻想史 -现代史 ...

  2. taobao_api项目开坑,自主完成淘宝主要接口的开发-版本:卖家版(非淘宝api)

    项目名称:taobao_api 项目目的:独立实现各个淘宝操作的相关api,不依赖淘宝提供的api,而是自己实现接口 前期实现接口:已付款订单查询(自动更新), 订单发货 , 订单备注 应用场景:中小 ...

  3. 【CSP膜你赛】大逃亡

    题目描述 魔王撒旦为了建立魔物的乐土,率领亚多拉玛雷克.艾谢尔.路西菲尔.以 及马纳果达这四位恶魔大元帅进攻人类世界.然而此时手持圣剑的勇者艾米莉亚出现了.  战败的魔王逃跑时穿越到了地球,以真奥贞夫 ...

  4. 【CSP膜你赛】ATM

    题目描述 小沈阳在小品里说过:“人生最痛苦的事情是人死了,钱还没花掉”. 于是小宋(80 岁)决定要将所有的储蓄从 ATM 机中取出花光. 小宋忘记 了她有多少存款(银行卡密码她是记得的 2333), ...

  5. 【CSP膜你赛】柠檬的密码(manacher 二分 单调性 st表)

    题目描述 Lemon觉得他需要一个复杂的密码来保证他的帐号的安全.他经过多日思考,决定使用一个长度为奇数的回文串来作为他的密码.  但是这个回文串太长了,Lemon记不住,于是Lemon决定把它记在本 ...

  6. 【良心noip膜你赛】总结

    一点都不良心!!!! AK 快乐爆零快乐!!! 1. A. value512mb 1s规定一个区间的价值为这个区间中所有数 and 起来的值与这个区间所有数 or 起来的值的乘积.例如 3 个数 2, ...

  7. EZ 2018 1 21 2018noip第五次膜你赛

    这次分数普遍偏高,而且yu'ben'ao又AK了! 但是最后一题莫名爆0让我很感伤啊(搓了1个多小时的20分暴力)! 难度偏低,主要是T2没剪枝,炸了3个点. T1 这种SB题恐怕是千年难遇了,PJ- ...

  8. EZ 2018 01 14 2018noip第四次膜你赛

    这次惨烈的炸了个精光(只有20),然后对我的OI想法造成了巨大的转折. (以上有点作,其实我只是再也不用vector存图了而已(用邻接表)) 难度很不均匀,而且题型很狗(还有结论题???) T1 坑人 ...

  9. EZ 2017 12 30 2018noip第二次膜你赛

    去年的比赛了,然而今天才改好. 总体难度适中,有大佬AK. 主要是自己SB第二题没想出来,然后又是可怜的100来分. T1 一道二分+数学的题目. 我们可以二分叫的次数,然后用公式(等差数列,公差都是 ...

随机推荐

  1. 用户与安全 -(1)Linux用户及组管理

    关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 前言 Linux 是多用户多任务操作系统,换句话说,Linux 系统支持多个用户在同一时间内登 ...

  2. Kubernetes容器之间的通信浅谈

    公众号关注 「开源Linux」 回复「学习」,有我为您特别筛选的学习资料~ 作者: Matt Zand 和 Jim Sullivan 译者: 穿过生命散发芬芳F Kubernetes是一个容器化的解决 ...

  3. 使用 Swoole 加速你的 CMS 系统,并实现热更新 (基于 Laravel 框架)

    主题:使用 Swoole 加速你的 CMS 系统,并实现热更新 关于 Swoole 的简介不再在此赘述,各位可以自行查看官网的文档进行详细的了解. 本文以 MyCms 为例,简要说明 Swoole 结 ...

  4. 面渣逆袭:Redis连环五十二问,图文详解,这下面试稳了!

    大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis--不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的NoSQL数据库. ...

  5. CRM项目的整理---第一篇

    CRM:cunstomer relationship management  客户管理系统 1.项目的使用者:销售  班主任    讲师  助教 2.项目的需求分析 2.1.注册 2.2.登录 2.3 ...

  6. 超全面!1.5w字总结50个Java经典基础面试题(已根据知识点分类)

    大家好,我是fancy. 在面试中将基础问题回答好就是成功的一半. 我总结了50道经典的Java基础面试题,里面包含面试要回答的知识重点,并且我根据知识类型进行了分类,可以说非常全面了. 小伙伴们点赞 ...

  7. 石油储运生产 2D 可视化,组态应用赋能工业智慧发展

    前言 当前,国际油价低位徘徊导致各国石油化工行业投资大幅缩减,石油化工建设行业竞争环境日趋严峻,施工企业的利润空间也被不断压缩.内外交困的环境下,促使企业采取更有效的管理手段来提高效率和降低成本.石油 ...

  8. Vulnhub-earth

    1.信息收集 1.1找到目标主机ip vulnhub靶场通用的技巧 这里我们靶场是nat模式的 所以肯定就是在我们自己设置的一个网段范围内,我这里nat本机的地址是10.1.1.1 所处的网段就是10 ...

  9. react 疑问集锦

    在 setState 后未 re-render function component 初始化调用接口

  10. 【算法】基数排序(Radix Sort)(十)

    基数排序(Radix Sort) 基数排序是按照低位先排序,然后收集:再按照高位排序,然后再收集:依次类推,直到最高位.有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序.最后的次序就 ...