力扣第 115 场双周赛(完全背包,多重背包,前缀和,最长上升子序列模型)
模拟题,记录一个k值,表示上一次记录到哪里了。若遇到prev则移动k;否则重置k;
class Solution { public: vector<int> lastVisitedIntegers(vector<string>& words) { vector<int> nums, res; int k = 0; for(auto &w: words) { if(w == "prev") { k ++ ; if(k > nums.size()) res.push_back(-1); else res.push_back(nums[nums.size() - k]); } else { nums.push_back(stoi(w)); k = 0; } } return res; } };
本题可以用贪心,也可以用dp。
贪心方法:我们可以把groups进行集合的划分,分为一个个由若干0和若干1组成的串。在划分后的集合随便取出一个数即可(这里我们取第一个)。
class Solution { public: vector<string> getWordsInLongestSubsequence(int n, vector<string>& words, vector<int>& groups) { vector<string> res; for(int i = 0, last = -1; i < n; i ++ ) { if(groups[i] != last) { res.push_back(words[i]); last = groups[i]; } } return res; } };
第三题是一种记录方案的最长子序列问题,其数据范围为1000,可以用最长上升子序列的模板。
class Solution { public: bool check(string& a, string &b) { if(a.size() != b.size()) return false; int cnt = 0; for(int i = 0; i < a.size(); i ++ ) { if(a[i] != b[i]) cnt ++ ; } return cnt == 1; } vector<string> getWordsInLongestSubsequence(int n, vector<string>& words, vector<int>& groups) { vector<int> f(n, 0), g(n, -1); int k = 0; for(int i = 0; i < n; i ++ ) { f[i] = 1; for(int j = 0; j < i; j ++ ) { if(groups[i] != groups[j] && check(words[i], words[j])) { if(f[i] < f[j] + 1) { f[i] = f[j] + 1; g[i] = j; } } } if(f[i] > f[k]) k = i; } vector<string> res; while(k != -1) { res.push_back(words[k]); k = g[k]; } reverse(res.begin(), res.end()); return res; } };
完全背包,多重背包,前缀和的应用。
每个数字抽象为一个物品,体积为数值。
状态定义 f[i][j]:从前i项中选,体积恰好为j的方案数。
f[i][j] = f[i-1][j] + f[i-1][j-i] + f[i-1][j- i * 2] + ..... + f[i-1][j - cnt * i (如果它大于0)]
可以利用完全背包 + 前缀和来进行计算。
完全背包g[i][j] 可以取无限个i 。其对应关系为 f[i][j] = g[i][j] - g[i][j - (cnt[i] + 1) * i <- g(r) - g(l - 1)
class Solution { public: const int N = 20010, MOD = 1e9 + 7; int countSubMultisets(vector<int>& nums, int l, int r) { vector<int> cnt(N, 0), f(r + 1), g(r + 1); for(auto x: nums) cnt[x] ++ ; f[0] = 1; for(int i = 1; i < N; i ++ ) { if(!cnt[i]) continue; for(int j = 0; j <= r; j ++ ) g[j] = 0; for(int j = 0; j <= r; j ++ ) { g[j] = f[j]; if(j >= i) g[j] = (g[j] + g[j - i]) % MOD; } for(int j = 0; j <= r; j ++ ) { f[j] = g[j]; if(j >= (cnt[i] + 1) * i) f[j] = (f[j] - g[j - (cnt[i] + 1) * i]) % MOD; } } int res = 0; for(int i = l; i <= r; i ++ ) res = (res + f[i]) % MOD; res = res * (cnt[0] + 1ll) % MOD; res = (res + MOD) % MOD; return res; } };