20200725005909
如果一直 TLE,就看第三章。
物品可能的种类有 k k k 种,编号为 [ 1 , k ] [1,k] [1,k]。
有 n n n 件物品,第 i i i 件物品属于某一种类 t i t_i ti 并拥有四个非负整数的属性值 a i , b i , c i , d i a_i,b_i,c_i,d_i ai,bi,ci,di。
现在,我们对每一种类最多取其中一件物品,最终得到所取出物品的集合 S S S(元素为所取物品的编号),则我们的总收获为
D M G = ( 100 + ∑ i ∈ S a i ) ( 100 + ∑ i ∈ S b i ) ( 100 + ∑ i ∈ S c i ) ( 100 + ∑ i ∈ S d i ) DMG = (100+\sum_{i\in S} a_i)(100+\sum_{i\in S} b_i)(100+\sum_{i\in S} c_i)(100+\sum_{i\in S} d_i) DMG=(100+i∈S∑ai)(100+i∈S∑bi)(100+i∈S∑ci)(100+i∈S∑di)
求能得到的最大收获。
样 例 数 T ≤ 10 ; 样例数 T\leq 10; 样例数T≤10;
n , k ≤ 50 ; 1 ≤ t i ≤ k ; 0 ≤ a i , b i , c i , d i ≤ 100 ; n,k\leq 50; 1\leq t_i\leq k; 0\leq a_i,b_i,c_i,d_i\leq 100; n,k≤50;1≤ti≤k;0≤ai,bi,ci,di≤100;
注意,样例输入隐含了重要题意信息:
1
6 4
1 17 25 10 0
2 0 0 25 14
4 17 0 21 0
1 5 22 0 10
2 0 16 20 0
4 37 0 0 0
发现数据较小,先考虑暴力搜索,下面证明其可行性。
首先,既然属性值非负,那么我们对每个种类都应取一件物品,除非这一种类不含任何物品。
当总共有 k = k 0 k=k_0 k=k0 种种类时,最大复杂度是多少?设 第 i i i 种有 c n t i cnt_i cnti 件物品,则复杂度为 Π i = 1 k c n t i \Pi_{i=1}^k cnt_i Πi=1kcnti。显然,当每种物品数量比较均衡时上述乘积达到最大。具体来说,由于每组平均有 n k \frac{n}{k} kn 件物品,我们可令含有 ⌈ n k ⌉ \lceil \frac{n}{k} \rceil ⌈kn⌉ 件物品的种类数为 n m o d k n\mod k nmodk,其余种类含有 ⌊ n k ⌋ \lfloor \frac{n}{k}\rfloor ⌊kn⌋ 件物品,则最为平均。
然后我们再对 k 0 k_0 k0 取 [ 1 , 50 ] [1,50] [1,50] 各值,发现当种类数 k 0 = 17 k_0=17 k0=17 时复杂度最大:
则暴力搜索的单样例复杂度约 8.6 ∗ 1 0 7 8.6*10^7 8.6∗107,总复杂度达 8.6 ∗ 1 0 8 8.6*10^8 8.6∗108,本地电脑实测可以过。
然而,交上去却TLE,对此我们进行了各类优化:递归改为用栈循环并进一步改成手写栈、减少 long long
运算(因为在最后一步相乘得答案前,加法不会爆 int
)都没用。
仔细研究样例,会发现虽然输入 k = 4 k=4 k=4,但实际物品种类只有三种,即允许有种类是不含任何物品的(第二章也稍稍提到了)。再看官方题解和各博客,发现多次提及 c n t i = 0 cnt_i=0 cnti=0 的种类应跳过。这便引出了此题又一个巨大的常数……
以种类数为 17 17 17 为例,此时最坏情况有 16 16 16 个种类含三件物品、 1 1 1 个种类含两件物品。然而当输入 k = 50 k=50 k=50 时,就会有 33 33 33 个空的种类(不含任何物品)!把dfs过程视为一棵树,我们本应递归 17 17 17 层访问 8.6 ∗ 1 0 8 8.6*10^8 8.6∗108 个叶子节点(可能情况),但如果这 33 33 33 个空种类(空递归层)造成的树链被加在了每个叶子的下方(这是最坏情况,当然这些链也可能加在中间层),就会增加 8.6 ∗ 1 0 8 ∗ 33 8.6*10^8*33 8.6∗108∗33 次递归调用(树上节点)!这只是举例,最坏情况也不一定发生在 17 17 17 种种类时呢?没有进一步计算探究了。
解决方法很简单,每组样例只需要在dfs前花费 O ( 50 ) O(50) O(50) 遍历一遍所有种类,用链表记录非空种类,后续递归只关注链表上的种类即可。
#include
#include
#include
#define ll long long
int t[55], a1[55], b1[55], c1[55], d1[55];
std::vector<int> items[55]; // items[i] stores the (id of) items of the i-th type.
int next_type[55];
int last_type;
ll max_ans;
void dfs(int ind , int a , int b , int c , int d){
if(ind==0){
max_ans = std::max( max_ans , 1LL*a*b*c*d );
return;
}
for(int i=0 ; i<items[ind].size() ; ++i){
int j=items[ind][i];
dfs(next_type[ind] , a+a1[j] , b+b1[j] , c+c1[j] , d+d1[j]);
}
}
int main(){
int T;
scanf("%d" , &T);
while(T--){
int n,k;
scanf("%d%d" , &n , &k);
for(int i=1 ; i<=k ; ++i) items[i].clear();
for(int i=1 ; i<=n ; ++i){
scanf("%d%d%d%d%d" , &t[i] , &a1[i] , &b1[i] , &c1[i] , &d1[i]);
items[t[i]].push_back(i);
}
last_type=51;
for(int i=k ; i>=1 ; --i){
if(items[i].size()==0) continue;
next_type[last_type]=i;
last_type = i;
}
next_type[last_type]=0;
max_ans=0;
dfs(next_type[51] , 100 , 100 , 100 , 100);
printf("%lld\n" , max_ans);
}
return 0;
}