这几天做了几道题目, 就写一写,题目真得很~好。
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, 那么就无解了。