gold_ 背包DP, memory_KMP

来源:互联网 发布:spss数据结果分析报告 编辑:程序博客网 时间:2024/06/01 08:19

这几天做了几道题目, 就写一写,题目真得很~好。

gold: 给出S个背包, 每个背包容量为Y, 和N件物品,可以去任意次, 每个物品有一个价值V和重量W,且知道合并两个背包的代价为C, 问价值和最大是多少。

50%:  S*Y<=1000,  N<=1000, 

100%: S,N<=1000, Y<=1000000000, W<=18


对于50%的数据, 做两次DP即可。

Gi表示容量为i的背包能放下的最大价值为多少, 转移方程为 G[i ]= G [i- Wj] +Vj   时间复杂度为O(N*S*Y)

Fi表示使用i个背包可以达到的最大价值, Fi = Fj-1 - (i-j)*c + G[ (i-j+1)*Y ],即前j-1个背包达到的最大价值 加上 后 i-j+1个背包合并的价值。 时间O(S^2)


但是100%的数据的Y一维巨大,而且F方程已经不能再优化了,再看看W<=18, 就说最多物品也只有18件。(价值一样的选价值最大的)

先做做G的递推方程, 发现到某一时刻以后, 整个G变得有规律了。

之前我们做背包时想过贪心的方法(总选性价比最高的物品), 我们可以证明我们在递推G时到某一时刻,

后面的i总有 G[i]= G[i-W]+V { W,V是性价比最高的 重量与价值 }

这样就可以推出 G[k*y]的值了。


因为递推G的最坏时间复杂度为V^3, 所以 是不会超时的~~~

memory : 给出一个长度为N的字符串, 求一个长度最大的字串, 既是 前缀, 又是后缀, 又在中间出现过。 N<= 10 ^ 6

这道题可以用hash来解决。

首先用hash找出所有 i 是满足 前缀==后缀【顺序扫描】, 这里的i是满足二分性质的, 可以再扫一遍来判断是否合法。


KMP !!
KMP适用于串的模式匹配, 中心思想是对于子串中求出Fail指针, 使得在不匹配时调整子串的位置。

fail数组有一个性质, 对于 Fail i,那么1~i的子串中, 长度为Fail i的前缀等于后缀。

那么我们求的就是Fail N, 但是还要判断一下是否有一个fail j=fail N, 若有, 那么Fail N就是答案, 否则 答案就是Fail [ fail [N]] 【这保证了中间】。

若最后求的答案为0 或长度小于3, 那么就无解了。 


原创粉丝点击