A和B都是简单题
C. Dima and Salad
题意:给出n个a[i],再给出与a[i]对应的b[i],求一组序列,在sum(a[j]) = k * sum((b[j]) (1 <=j <= n)时,sum(a[j])最大。
思路:就是一个代价有负数的01背包,求代价刚好为0时的最大值。我们来看,如果代价全是非负数时,我们的代码:
for(int i = 1;i <= n;i++)
for(int v = max;v >= cost[i];v--)
dp[v] = max(dp[v],dp[v - cost[i]] + value[i])
此时,如果cost[i]是负数,那么,dp[v]中的v就有可能是负的;当cost[i] >= 0时,跟经典的01背包没有差别,如果dp[v]中v允许为负,以v = -9为例,dp[-9] = max(dp[-9 - cost[i]] + value[i]);而如果cost[i] < 0,计算dp[v]的顺序,即第二层循环就不能一样了,为什么,因为当cost[i] < 0时,-9 - cost[i] > -9,也就是说,应该是从比-9更大的代价上转移来的。所以,第二层应该为
for(int v = 0;v <= max + cost[i];v++)
好了,循环顺序搞清楚了,我们再来看dp[v],编程语言不允许v < 0,那我们可以将v水平右移变成v + x,本来 v = 0的时候是原点,现在原点相应变成v + x。然后就可以跟01背包一样处理了。
D. Dima and Trap Graph
题意:每条边有一个范围[l, r],我们有一个忠诚度x,当l <= x <= r时,就可以通过这条边,现在要从点1走到点n,问x最大的区间是多少,即lt <= x <= rt,求max(lt - rt)。
思路:其实,这题最重要的特性就是,lt和rt必定是某一条或某两条边的l 和 r。由此特性,我们可以对所有边的左区间值进行遍历,遍历时,对右区间进行二分,然后就看能否用此时查找的区间值从1走到n就行了。