题目背景

kkksc03 的大学生活非常的颓废,平时根本不学习。但是,临近期末考试,他必须要开始抱佛脚,以求不挂科。

题目描述

这次期末考试,kkksc03 需要考 44 科。因此要开始刷习题集,每科都有一个习题集,分别有 s1,s2,s3,s4s_1,s_2,s_3,s_4 道题目,完成每道题目需要一些时间,可能不等(A1,A2,,As1A_1,A_2,\cdots,A_{s_1}B1,B2,,Bs2B_1,B_2,\cdots,B_{s_2}C1,C2,,Cs3C_1,C_2,\cdots,C_{s_3}D1,D2,,Ds4D_1,D_2,\ldots,D_{s_4})。
kkksc03 有一个能力,他的左右两个大脑可以同时计算 22 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科地复习。
由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。

输入格式

本题包含 55 行数据:第 11 行,为四个正整数 s1,s2,s3,s4s_1,s_2,s_3,s_4
22 行,为 A1,A2,,As1A_1,A_2,\cdots,A_{s_1}s1s_1 个数,表示第一科习题集每道题目所消耗的时间。
33 行,为 B1,B2,,Bs2B_1,B_2,\cdots,B_{s_2}s2s_2 个数。
44 行,为 C1,C2,,Cs3C_1,C_2,\cdots,C_{s_3}s3s_3 个数。
55 行,为 D1,D2,,Ds4D_1,D_2,\cdots,D_{s_4}s4s_4 个数,意思均同上。

输出格式

输出一行,为复习完毕最短时间。

输入输出样例

输入 #1

1
2
3
4
5
1 2 1 3		
5
4 3
6
2 4 3

输出 #1

1
20

说明/提示

1s1,s2,s3,s4201\leq s_1,s_2,s_3,s_4\leq 20
1A1,A2,,As1,B1,B2,,Bs2,C1,C2,,Cs3,D1,D2,,Ds4601\leq A_1,A_2,\cdots,A_{s_1},B_1,B_2,\cdots,B_{s_2},C_1,C_2,\cdots,C_{s_3},D_1,D_2,\cdots,D_{s_4}\leq60

思路

摘自洛谷题解
四个科目其实就是四组数据,考虑一个科目单独分析。
显然若当前要处理的问题的时间和为 tt,最佳答案是 t2\frac{t}{2},也就是两边脑所耗时间差为 00。于是现在要求的问题就是使得两边脑所耗时间差尽量小。
如果只考虑一边脑耗时,由于两边脑是对称的,我们假设这个耗时肯定比 t2\frac{t}{2} 小。那么我们要使这个耗时尽量接近 t2\frac{t}{2}
然后又想到了背包。保证比 t2\frac{t}{2} 小,又要使取得的时间尽量大,可以转化为一个体积与价值相同的背包问题。背包容量为 t2\frac{t}{2},一个题目的体积和价值相等,都是所耗的时间。
假设背包求得的最大价值为 vv,显然另一个脑耗时为 tvt-v,则总耗时为 max(v,tv)\max(v,t-v)
四组数据按照相同方法处理。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/******************************************************************
Copyright: 11D_Beyonder All Rights Reserved
Author: 11D_Beyonder
Problem ID: Luogu P2392
Date: 2021 Mar. 15th
Description: 01-Bag
*******************************************************************/
#include<iostream>
#include<cstring>
typedef long long ll;
using namespace std;
const int mod = 1e9 + 7;
int s1, s2, s3, s4;
int ans(int n) {
int* v=new int[n+1];
int volume=0;
for(int i=1;i<=n;i++){
cin>>v[i];
volume+=v[i];
}
int* f=new int[volume/2+1];
memset(f,0,sizeof(int)*(volume/2+1));
for(int i=1;i<=n;i++){
for(int j=volume>>1;j>=v[i];j--){
f[j]=max(f[j],f[j-v[i]]+v[i]);
}
}
const int ans=max(f[volume>>1],volume-f[volume>>1]);
delete[]f;
delete[]v;
return ans;
}
int main() {
cin >> s1 >> s2 >> s3 >> s4;
cout << ans(s1) + ans(s2) + ans(s3) + ans(s4) << endl;
return 0;
}