有n[1, 10]
个 不等长的数组长度2e5
,且每个数组,都是sort
的
[1, 10]
[2, 3, 10]
[4, 5, 6, 10]
你需要从这n个数组中,选择1个元素,即一共选n个元素(且该选择方案,n个元素和是最大的)
显然,每个数组选择最后元素,这种方案是最大的。
有m[1, 1e5]
个ban方案
(每个方案长度是n 表示对这n个数组的选择情况),即这些方案,是不能选择的。
从上图来看,最优方案依次是: 10,10,10
10,10,6
…
如果我们ban掉:[2,3,4]
。 则最大方案是:[2,3,3] = 10,10,6
最终,输出最大的方案(如果有多个,则任意即可。) 答案保证有解
先看个错误的思路:
令这n个数组的长度,依次是:n1, n2, n3, ...
令最初i = n1, j = n2, z = n3
FOR(st, 0, (1<<n)-1, 1)
,如果二进制是1,则往左退一位。
如果,所有st都是ban的,则让i--, j--, z--
即:如果i,j,z
i-1,j,z
i,j-1,z
i,j,z-1
i-1,j-1,z
i-1,j,z-1
i,j-1,z-1
i-1,j-1,z-1
都是baned。
则让i--, j--, z--
,说明: 答案里,一定没有n1, n2, n3
。
很容易会这么想。
其实不然。
[1, 1, 100]
[1, 1, 100]
[1, 1, 100]
比如,ban掉所有的方案,只剩下:3, 3, 1
。 即,最终答案是100, 100, 1
。
即,这其实是很复杂的。 不是线性扫描就能做到的。
唉,CF的题,思维跳跃性 都比较高…
由于肯定有解,比如答案是i, j, k
(如果:i+1, j, k
没有ban,则: i+1,j,k
是优于i,j,k
的!)
(如果:i, j+1, k
没有ban,则: i,j+1,k
是优于i,j,k
的!)
(如果:i+1, j+1, k
没有ban,则:i+1, j+1, k
是优于i,j,k
的!)
我们用st = [1, (1<<n)-1]
,来表示,上面的(+1)操作。
则,对于所有的ans + st
这个方案
- 要么不存在。(比如,ans中 某个已经在最右侧) + (st)后,就溢出了
这种方案属于非法的。 - 要么,该方案,一定是ban的!!! (因为,该方案 优于 ans)
假如说:
- 所有的
ans + st
方案,都是非法的。 说明: ans全部都在最右侧!!!
这种情况,我们特判掉。
否则,所有的ans + st
方案里,至少存在1个方案, 他是合法 没有溢出的。
而且,这个方案,是ban的!!!
那么此时,就可以反向: 根据所有ban,然后 - st
后,获得一个方案(如果该方案 是没有ban的。则该方案 一定会找到ans)
会用到: 判断一个方案,是否在ban里。(哈希二分)
时间:(枚举所有ban1e5
) * (st=1024
)* (二分20 * k
) 超时 (k是:哈希每次判断大小的时间,即vector的长度)
这里要优化。
其实,这里的st, 不需要是2^n
! 只需要n (1, 2, 4, 8, 16..)
即可。
比如我们看,有>=2个1的st
比如一个ban的方案:3, 3, 2
, 他通过st = 3
找到了 ans2, 2, 2
。
又因为, ans的所有的st
都是ban的。
即此时有:3, 2, 2
,一定是ban的!!
故,通过 ban的方案3,2,2
,配合st = 1
,也可以找到ans!!!
因此,st 从原来的2^n
,变成n
!!
由于每次需要判断,一个方案 是否在 ban里。 (即,暂时先用 简单的 哈希二分)
代码是:
比如有n个数组,每个数组长度是`n1, n2, n3, ...`
VE< VE<int> > ban( m); ' 共m个ban,每个ban长度是n。这是题目录入的 '
sort( ban.begin(), ban.end()); ' 哈希二分 '
{ ' 特判 '
if( binary_search( ban, {n1,n2,n3,...}) == false){
答案是: (n1, n2, n3...);
return;
}
}
for( const auto & _ban : ban){
auto _t = _ban;
' 不可以直接用_ban,因为对_ban进行修改,意味着 修改了ban,而ban是不能修改的!!'
' 因此,在for循环时,写上const,是最好的!!! '
for( auto & i : _t){
if( i != 1){
-- i; ' 此时的_t,一定会遇到 ans'
if( binary_search( ban, _t) == false){
获取_t对应的总和,尝试更新ans。
}
++ i;
}
}
}
总时间是: m * n * log(m) * k(ve的长度)
= 1e5 * 10 * 20 * n
。
思路非常新颖!!!
即反过来, 根据ban,去(枚举)ans。