fork download
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. // =====================================================================
  5. // DP CLASSIC
  6. // All Functions and Tricks
  7. // Used in ECPC and ACPC competitions and advanced cases
  8. // =====================================================================
  9.  
  10. // Global constant used in many DP functions (modulo for combinatorics, etc.)
  11. // You must define MOD before using any function that relies on it.
  12. const long long MOD = 1000000007LL;
  13.  
  14. // --------------------------------------------
  15. // 1) Fibonacci (with memoization / bottom-up)
  16. // --------------------------------------------
  17. /*
  18.  * This section provides functions to compute Fibonacci numbers.
  19.  * - fib(n): top-down memoized recursion (requires resetting fibMemo to -1).
  20.  * - buildFib(n): bottom-up iterative, returns vector of fib[0..n].
  21.  * - fibOptimized(n): space-optimized O(1) iterative.
  22.  * - fibMatrix(n): matrix exponentiation O(log n) for large n.
  23.  * Use fibOptimized for small n, fibMatrix for n > 1e7.
  24.  * Note: global fibMemo must be reset using resetMemo().
  25.  */
  26.  
  27. const int MAXN = 1e6 + 5;
  28. long long fibMemo[MAXN];
  29.  
  30. /*
  31.  * Function: fib (recursive memoized)
  32.  * Description: Computes the n-th Fibonacci number using top-down DP with memoization.
  33.  * Parameters:
  34.  * n - non-negative integer (index of Fibonacci number)
  35.  * Returns: long long - the n-th Fibonacci number (F(0)=0, F(1)=1)
  36.  * Time Complexity: O(n)
  37.  * Space Complexity: O(n) for the memo array
  38.  * Constraints: n < MAXN (1e6+5)
  39.  * Notes: The global array fibMemo must be initialized to -1 before calling.
  40.  * Use resetMemo(fibMemo, MAXN) to reset.
  41.  */
  42. long long fib(int n) {
  43. if (n <= 1) return n;
  44. if (fibMemo[n] != -1) return fibMemo[n];
  45. return fibMemo[n] = fib(n - 1) + fib(n - 2);
  46. }
  47.  
  48. /*
  49.  * Function: buildFib (iterative)
  50.  * Description: Builds the Fibonacci sequence up to the n-th term using bottom-up DP.
  51.  * Parameters:
  52.  * n - non-negative integer (maximum index)
  53.  * Returns: vector<long long> - fib[0..n] where fib[i] = i-th Fibonacci number
  54.  * Time Complexity: O(n)
  55.  * Space Complexity: O(n)
  56.  * Constraints: n >= 0
  57.  * Notes: None
  58.  */
  59. vector<long long> buildFib(int n) {
  60. vector<long long> fib(n + 1);
  61. fib[0] = 0;
  62. if (n >= 1) fib[1] = 1;
  63. for (int i = 2; i <= n; i++) fib[i] = fib[i - 1] + fib[i - 2];
  64. return fib;
  65. }
  66.  
  67. // --------------------------------------------
  68. // 2) Knapsack (0/1)
  69. // --------------------------------------------
  70. /*
  71.  * This section solves the classic 0/1 knapsack problem.
  72.  * - knapsack01: standard DP with O(n*W) time and O(W) space.
  73.  * - knapsack01ByValue: alternative when capacity W is huge but total value is small.
  74.  * Both assume each item is used at most once.
  75.  */
  76.  
  77. /*
  78.  * Function: knapsack01
  79.  * Description: Solves the 0/1 knapsack problem: maximize total value with a weight capacity.
  80.  * Parameters:
  81.  * weight - vector<int> of item weights (size n)
  82.  * value - vector<int> of item values (size n)
  83.  * W - int capacity of knapsack
  84.  * Returns: long long - maximum total value achievable
  85.  * Time Complexity: O(n * W)
  86.  * Space Complexity: O(W) (using 1D DP array)
  87.  * Constraints: n and W can be up to ~10^4; weight[i] >= 0, W >= 0
  88.  * Notes: Items are distinct (each used at most once).
  89.  */
  90. long long knapsack01(const vector<int>& weight, const vector<int>& value, int W) {
  91. int n = weight.size();
  92. vector<long long> dp(W + 1, 0);
  93. for (int i = 0; i < n; i++) {
  94. for (int w = W; w >= weight[i]; w--) {
  95. dp[w] = max(dp[w], dp[w - weight[i]] + value[i]);
  96. }
  97. }
  98. return dp[W];
  99. }
  100.  
  101. /*
  102.  * Function: knapsack01ByValue
  103.  * Description: Solves 0/1 knapsack when capacity W is very large but total value is small.
  104.  * It minimizes weight for each possible total value.
  105.  * Parameters:
  106.  * weight - vector<int> of item weights (size n)
  107.  * value - vector<int> of item values (size n)
  108.  * W - int capacity of knapsack
  109.  * Returns: long long - maximum total value that fits in capacity W
  110.  * Time Complexity: O(n * maxVal), where maxVal = sum of all values
  111.  * Space Complexity: O(maxVal)
  112.  * Constraints: sum of values should be manageable (e.g., <= 10^5) to avoid memory blow.
  113.  * Notes: Use this when W is huge and values are small.
  114.  */
  115. long long knapsack01ByValue(const vector<int>& weight, const vector<int>& value, int W) {
  116. int n = weight.size();
  117. int maxVal = accumulate(value.begin(), value.end(), 0);
  118. const long long INF = 1e18;
  119. vector<long long> dp(maxVal + 1, INF);
  120. dp[0] = 0;
  121. for (int i = 0; i < n; i++) {
  122. for (int v = maxVal; v >= value[i]; v--) {
  123. dp[v] = min(dp[v], dp[v - value[i]] + weight[i]);
  124. }
  125. }
  126. long long ans = 0;
  127. for (int v = 0; v <= maxVal; v++) {
  128. if (dp[v] <= W) ans = v;
  129. }
  130. return ans;
  131. }
  132.  
  133. // --------------------------------------------
  134. // 3) Unbounded Knapsack (Complete)
  135. // --------------------------------------------
  136. /*
  137.  * Solves the unbounded knapsack problem: each item can be taken any number of times.
  138.  * - knapsackUnbounded: O(n*W) time, O(W) space.
  139.  */
  140.  
  141. long long knapsackUnbounded(const vector<int>& weight, const vector<int>& value, int W) {
  142. int n = weight.size();
  143. vector<long long> dp(W + 1, 0);
  144. for (int w = 0; w <= W; w++) {
  145. for (int i = 0; i < n; i++) {
  146. if (w >= weight[i]) {
  147. dp[w] = max(dp[w], dp[w - weight[i]] + value[i]);
  148. }
  149. }
  150. }
  151. return dp[W];
  152. }
  153.  
  154. // --------------------------------------------
  155. // 4) LIS - Longest Increasing Subsequence
  156. // O(N log N) using binary search
  157. // --------------------------------------------
  158. /*
  159.  * Functions for longest increasing subsequence and its variants.
  160.  * - LIS: strict increasing, O(n log n).
  161.  * - LNDS: non-decreasing (allows equal values), O(n log n).
  162.  * - LISReconstruct: reconstructs one LIS using O(n^2) DP (for n ≤ 5000).
  163.  * Use LIS for length only; use LISReconstruct for the actual sequence when n is small.
  164.  */
  165.  
  166. int LIS(const vector<int>& arr) {
  167. vector<int> lis;
  168. for (int x : arr) {
  169. auto it = lower_bound(lis.begin(), lis.end(), x);
  170. if (it == lis.end()) lis.push_back(x);
  171. else *it = x;
  172. }
  173. return lis.size();
  174. }
  175.  
  176. int LNDS(const vector<int>& arr) {
  177. vector<int> lis;
  178. for (int x : arr) {
  179. auto it = upper_bound(lis.begin(), lis.end(), x);
  180. if (it == lis.end()) lis.push_back(x);
  181. else *it = x;
  182. }
  183. return lis.size();
  184. }
  185.  
  186. vector<int> LISReconstruct(const vector<int>& arr) {
  187. int n = arr.size();
  188. vector<int> dp(n, 1), parent(n, -1);
  189. int maxLen = 1, bestIdx = 0;
  190. for (int i = 0; i < n; i++) {
  191. for (int j = 0; j < i; j++) {
  192. if (arr[j] < arr[i] && dp[j] + 1 > dp[i]) {
  193. dp[i] = dp[j] + 1;
  194. parent[i] = j;
  195. }
  196. }
  197. if (dp[i] > maxLen) {
  198. maxLen = dp[i];
  199. bestIdx = i;
  200. }
  201. }
  202. vector<int> seq;
  203. for (int i = bestIdx; i != -1; i = parent[i]) seq.push_back(arr[i]);
  204. reverse(seq.begin(), seq.end());
  205. return seq;
  206. }
  207.  
  208. // --------------------------------------------
  209. // 5) LCS - Longest Common Subsequence
  210. // --------------------------------------------
  211. /*
  212.  * Computes the longest common subsequence between two strings.
  213.  * - LCS: returns length.
  214.  * - LCSReconstruct: returns the actual LCS string.
  215.  * - LCS_Optimized: uses O(min(n,m)) space.
  216.  * Time complexity O(n*m) for all; space O(n*m) for reconstruction, O(min) for optimized.
  217.  * Use LCS_Optimized when memory is tight.
  218.  */
  219.  
  220. int LCS(const string& a, const string& b) {
  221. int n = a.size(), m = b.size();
  222. vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
  223. for (int i = 1; i <= n; i++) {
  224. for (int j = 1; j <= m; j++) {
  225. if (a[i - 1] == b[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
  226. else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
  227. }
  228. }
  229. return dp[n][m];
  230. }
  231.  
  232. string LCSReconstruct(const string& a, const string& b) {
  233. int n = a.size(), m = b.size();
  234. vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
  235. for (int i = 1; i <= n; i++)
  236. for (int j = 1; j <= m; j++) {
  237. if (a[i - 1] == b[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
  238. else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
  239. }
  240. string res;
  241. int i = n, j = m;
  242. while (i > 0 && j > 0) {
  243. if (a[i - 1] == b[j - 1]) {
  244. res.push_back(a[i - 1]);
  245. i--, j--;
  246. } else if (dp[i - 1][j] > dp[i][j - 1]) i--;
  247. else j--;
  248. }
  249. reverse(res.begin(), res.end());
  250. return res;
  251. }
  252.  
  253. // --------------------------------------------
  254. // 6) Coin Change (minimum coins & number of ways)
  255. // --------------------------------------------
  256. /*
  257.  * Solves coin change problems with unlimited supply.
  258.  * - coinChangeMin: minimum number of coins to make amount.
  259.  * - coinChangeWays: number of combinations to make amount (order does not matter).
  260.  * Both use O(amount * |coins|) time and O(amount) space.
  261.  */
  262.  
  263. int coinChangeMin(const vector<int>& coins, int amount) {
  264. const int INF = 1e9;
  265. vector<int> dp(amount + 1, INF);
  266. dp[0] = 0;
  267. for (int i = 1; i <= amount; i++) {
  268. for (int c : coins) {
  269. if (i >= c) dp[i] = min(dp[i], dp[i - c] + 1);
  270. }
  271. }
  272. return dp[amount] == INF ? -1 : dp[amount];
  273. }
  274.  
  275. long long coinChangeWays(const vector<int>& coins, int amount) {
  276. vector<long long> dp(amount + 1, 0);
  277. dp[0] = 1;
  278. for (int c : coins) {
  279. for (int i = c; i <= amount; i++) {
  280. dp[i] += dp[i - c];
  281. }
  282. }
  283. return dp[amount];
  284. }
  285.  
  286. // --------------------------------------------
  287. // 7) Matrix Chain Multiplication
  288. // --------------------------------------------
  289. /*
  290.  * Computes minimum scalar multiplications to multiply a chain of matrices.
  291.  * - matrixChainOrder: classic interval DP, O(n^3) time, O(n^2) space.
  292.  * n = dims.size() - 1 (number of matrices).
  293.  */
  294.  
  295. int matrixChainOrder(const vector<int>& dims) {
  296. int n = dims.size() - 1;
  297. vector<vector<int>> dp(n, vector<int>(n, 0));
  298. for (int len = 2; len <= n; len++) {
  299. for (int i = 0; i <= n - len; i++) {
  300. int j = i + len - 1;
  301. dp[i][j] = INT_MAX;
  302. for (int k = i; k < j; k++) {
  303. int cost = dp[i][k] + dp[k + 1][j] + dims[i] * dims[k + 1] * dims[j + 1];
  304. dp[i][j] = min(dp[i][j], cost);
  305. }
  306. }
  307. }
  308. return dp[0][n - 1];
  309. }
  310.  
  311. // --------------------------------------------
  312. // 8) Edit Distance (Levenshtein)
  313. // --------------------------------------------
  314. /*
  315.  * Computes minimum operations (insert, delete, replace) to transform one string into another.
  316.  * - editDistance: standard DP, O(n*m) time and space.
  317.  * Can be optimized to O(min(n,m)) space, but not implemented here.
  318.  */
  319.  
  320. int editDistance(const string& a, const string& b) {
  321. int n = a.size(), m = b.size();
  322. vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
  323. for (int i = 0; i <= n; i++) dp[i][0] = i;
  324. for (int j = 0; j <= m; j++) dp[0][j] = j;
  325. for (int i = 1; i <= n; i++) {
  326. for (int j = 1; j <= m; j++) {
  327. if (a[i - 1] == b[j - 1]) dp[i][j] = dp[i - 1][j - 1];
  328. else dp[i][j] = 1 + min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]});
  329. }
  330. }
  331. return dp[n][m];
  332. }
  333.  
  334. // --------------------------------------------
  335. // 9) DP on Grid / Number of Paths
  336. // --------------------------------------------
  337. /*
  338.  * Counting paths in a grid (right/down moves) and variants.
  339.  * - countPaths: number of paths from (0,0) to (n-1,m-1).
  340.  * - countPathsWithObstacles: with blocked cells.
  341.  * - minPathSum: minimum sum path.
  342.  * All use O(n*m) time and space (can be optimized to O(m)).
  343.  */
  344.  
  345. long long countPaths(int n, int m) {
  346. vector<vector<long long>> dp(n, vector<long long>(m, 0));
  347. dp[0][0] = 1;
  348. for (int i = 0; i < n; i++) {
  349. for (int j = 0; j < m; j++) {
  350. if (i > 0) dp[i][j] += dp[i - 1][j];
  351. if (j > 0) dp[i][j] += dp[i][j - 1];
  352. }
  353. }
  354. return dp[n - 1][m - 1];
  355. }
  356.  
  357. long long countPathsWithObstacles(const vector<vector<int>>& grid) {
  358. int n = grid.size(), m = grid[0].size();
  359. if (grid[0][0] == 1 || grid[n - 1][m - 1] == 1) return 0;
  360. vector<vector<long long>> dp(n, vector<long long>(m, 0));
  361. dp[0][0] = 1;
  362. for (int i = 0; i < n; i++) {
  363. for (int j = 0; j < m; j++) {
  364. if (grid[i][j] == 1) continue;
  365. if (i > 0) dp[i][j] += dp[i - 1][j];
  366. if (j > 0) dp[i][j] += dp[i][j - 1];
  367. }
  368. }
  369. return dp[n - 1][m - 1];
  370. }
  371.  
  372. int minPathSum(const vector<vector<int>>& grid) {
  373. int n = grid.size(), m = grid[0].size();
  374. vector<vector<int>> dp(n, vector<int>(m, INT_MAX));
  375. dp[0][0] = grid[0][0];
  376. for (int i = 0; i < n; i++) {
  377. for (int j = 0; j < m; j++) {
  378. if (i > 0) dp[i][j] = min(dp[i][j], dp[i - 1][j] + grid[i][j]);
  379. if (j > 0) dp[i][j] = min(dp[i][j], dp[i][j - 1] + grid[i][j]);
  380. }
  381. }
  382. return dp[n - 1][m - 1];
  383. }
  384.  
  385. // --------------------------------------------
  386. // 10) Maximum Subarray Sum (Kadane) and variants
  387. // --------------------------------------------
  388. /*
  389.  * Kadane's algorithm and its extensions.
  390.  * - maxSubarraySumKadane: classic O(n) for max sum (allows negative).
  391.  * - maxSubarraySumAtMostK: max sum with length at most K, O(n log n) using multiset.
  392.  * - maxSubarraySumAtMostK2: same but O(n) using deque.
  393.  * - maxProductSubarray: maximum product subarray, O(n).
  394.  */
  395.  
  396. long long maxSubarraySumKadane(const vector<long long>& arr) {
  397. long long maxEnd = 0, maxSum = LLONG_MIN;
  398. for (long long x : arr) {
  399. maxEnd = max(x, maxEnd + x);
  400. maxSum = max(maxSum, maxEnd);
  401. }
  402. return maxSum;
  403. }
  404.  
  405. long long maxSubarraySumAtMostK(const vector<long long>& arr, int K) {
  406. int n = arr.size();
  407. vector<long long> pref(n + 1, 0);
  408. for (int i = 0; i < n; i++) pref[i + 1] = pref[i] + arr[i];
  409. multiset<long long> ms;
  410. long long ans = LLONG_MIN;
  411. for (int i = 0; i <= n; i++) {
  412. if (i - K - 1 >= 0) ms.erase(ms.find(pref[i - K - 1]));
  413. if (!ms.empty()) ans = max(ans, pref[i] - *ms.begin());
  414. ms.insert(pref[i]);
  415. }
  416. return ans;
  417. }
  418.  
  419. long long maxSubarraySumAtMostK2(const vector<long long>& arr, int K) {
  420. int n = arr.size();
  421. vector<long long> pref(n + 1, 0);
  422. for (int i = 0; i < n; i++) pref[i + 1] = pref[i] + arr[i];
  423. deque<int> dq;
  424. dq.push_back(0);
  425. long long ans = LLONG_MIN;
  426. for (int i = 1; i <= n; i++) {
  427. while (!dq.empty() && dq.front() < i - K) dq.pop_front();
  428. ans = max(ans, pref[i] - pref[dq.front()]);
  429. while (!dq.empty() && pref[dq.back()] >= pref[i]) dq.pop_back();
  430. dq.push_back(i);
  431. }
  432. return ans;
  433. }
  434.  
  435. long long maxProductSubarray(const vector<int>& nums) {
  436. long long maxProd = nums[0], minProd = nums[0], ans = nums[0];
  437. for (int i = 1; i < (int)nums.size(); i++) {
  438. long long a = maxProd * nums[i];
  439. long long b = minProd * nums[i];
  440. maxProd = max({1LL * nums[i], a, b});
  441. minProd = min({1LL * nums[i], a, b});
  442. ans = max(ans, maxProd);
  443. }
  444. return ans;
  445. }
  446.  
  447. // --------------------------------------------
  448. // 11) DP with Bitmask (TSP, Hamiltonian Path)
  449. // --------------------------------------------
  450. /*
  451.  * Bitmask DP for problems with small n (n ≤ 20).
  452.  * - tsp: Traveling Salesman Problem (min cost Hamiltonian cycle).
  453.  * - countHamiltonianPaths: count number of Hamiltonian paths (directed graph).
  454.  * - countHamiltonianPaths(src, dst): with fixed start/end.
  455.  * Time O(2^n * n^2) or O(2^n * n).
  456.  */
  457.  
  458. int tsp(int n, const vector<vector<int>>& dist) {
  459. vector<vector<int>> dp(1 << n, vector<int>(n, INT_MAX));
  460. dp[1][0] = 0; // start from city 0
  461. for (int mask = 1; mask < (1 << n); mask++) {
  462. for (int u = 0; u < n; u++) {
  463. if (!(mask & (1 << u))) continue;
  464. if (dp[mask][u] == INT_MAX) continue;
  465. for (int v = 0; v < n; v++) {
  466. if (mask & (1 << v)) continue;
  467. int newMask = mask | (1 << v);
  468. dp[newMask][v] = min(dp[newMask][v], dp[mask][u] + dist[u][v]);
  469. }
  470. }
  471. }
  472. int fullMask = (1 << n) - 1;
  473. int ans = INT_MAX;
  474. for (int u = 0; u < n; u++) {
  475. if (dp[fullMask][u] != INT_MAX)
  476. ans = min(ans, dp[fullMask][u] + dist[u][0]);
  477. }
  478. return ans;
  479. }
  480.  
  481. long long countHamiltonianPaths(int n, const vector<vector<int>>& adj) {
  482. vector<vector<long long>> dp(1 << n, vector<long long>(n, 0));
  483. for (int i = 0; i < n; i++) dp[1 << i][i] = 1;
  484. for (int mask = 1; mask < (1 << n); mask++) {
  485. for (int u = 0; u < n; u++) {
  486. if (!(mask & (1 << u))) continue;
  487. if (dp[mask][u] == 0) continue;
  488. for (int v = 0; v < n; v++) {
  489. if (mask & (1 << v)) continue;
  490. if (!adj[u][v]) continue;
  491. dp[mask | (1 << v)][v] += dp[mask][u];
  492. }
  493. }
  494. }
  495. long long ans = 0;
  496. for (int i = 0; i < n; i++) ans += dp[(1 << n) - 1][i];
  497. return ans;
  498. }
  499.  
  500. long long countHamiltonianPaths(int n, int src, int dst, const vector<vector<int>>& adj) {
  501. vector<vector<long long>> dp(1 << n, vector<long long>(n, 0));
  502. dp[1 << src][src] = 1;
  503. for (int mask = 1; mask < (1 << n); mask++) {
  504. for (int u = 0; u < n; u++) {
  505. if (!(mask & (1 << u)) || dp[mask][u] == 0) continue;
  506. for (int v : adj[u]) {
  507. if (mask & (1 << v)) continue;
  508. dp[mask | (1 << v)][v] += dp[mask][u];
  509. }
  510. }
  511. }
  512. return dp[(1 << n) - 1][dst];
  513. }
  514.  
  515. // --------------------------------------------
  516. // 12) DP on Trees (Tree DP)
  517. // --------------------------------------------
  518. /*
  519.  * Tree DP functions.
  520.  * - dfsTreeDP: computes maximum independent set on a tree (global tree, dp0, dp1).
  521.  * - dfsDiameter: computes tree diameter (longest path).
  522.  * - dfsDown/dfsUp: rerooting DP to compute subtree contributions from all directions.
  523.  * Use global adjacency list 'tree'.
  524.  */
  525.  
  526. vector<vector<int>> tree;
  527. vector<int> dp0, dp1; // dp0 = not taken, dp1 = taken
  528.  
  529. void dfsTreeDP(int u, int p) {
  530. dp1[u] = 1;
  531. for (int v : tree[u]) {
  532. if (v == p) continue;
  533. dfsTreeDP(v, u);
  534. dp0[u] += max(dp0[v], dp1[v]);
  535. dp1[u] += dp0[v];
  536. }
  537. }
  538.  
  539. pair<int, int> dfsDiameter(int u, int p) {
  540. int max1 = 0, max2 = 0;
  541. for (int v : tree[u]) {
  542. if (v == p) continue;
  543. auto [d1, d2] = dfsDiameter(v, u);
  544. max1 = max(max1, d1 + 1);
  545. max2 = max(max2, d2);
  546. }
  547. return {max1, max(max2, max1 + max2)};
  548. }
  549.  
  550. vector<long long> dpDown, dpUp, ansTree; // for rerooting
  551.  
  552. void dfsDown(int u, int p) {
  553. dpDown[u] = 1; // example: count nodes in subtree
  554. for (int v : tree[u]) {
  555. if (v == p) continue;
  556. dfsDown(v, u);
  557. dpDown[u] += dpDown[v];
  558. }
  559. }
  560.  
  561. void dfsUp(int u, int p) {
  562. int deg = tree[u].size();
  563. vector<long long> pref(deg + 1, 0), suff(deg + 1, 0);
  564. for (int i = 0; i < deg; i++) {
  565. int v = tree[u][i];
  566. pref[i + 1] = pref[i] + (v == p ? dpUp[u] : dpDown[v]);
  567. }
  568. for (int i = deg - 1; i >= 0; i--) {
  569. int v = tree[u][i];
  570. suff[i] = suff[i + 1] + (v == p ? dpUp[u] : dpDown[v]);
  571. }
  572. for (int i = 0; i < deg; i++) {
  573. int v = tree[u][i];
  574. if (v == p) continue;
  575. dpUp[v] = 1 + pref[i] + suff[i + 1]; // combine all other branches
  576. dfsUp(v, u);
  577. }
  578. }
  579. // Usage: dfsDown(0, -1); dpUp[0] = 0; dfsUp(0, -1);
  580. // answer for each node = dpDown[u] + dpUp[u] (or other definitions)
  581.  
  582. // --------------------------------------------
  583. // 13) Digit DP
  584. // --------------------------------------------
  585. /*
  586.  * Digit DP for counting numbers with certain digit sum or other properties.
  587.  * - countDigitSum: counts numbers in [0, N] whose digit sum equals S.
  588.  * - countDigitSumWithLeadingZero: counts numbers with exactly target occurrences of digit 1 (or any digit).
  589.  * Uses memoization. Complexity O(len * sum * 2).
  590.  * Note: N ≤ 1e18 (len ≤ 19).
  591.  */
  592.  
  593. long long dpDigit[20][200][2];
  594. string numStr;
  595.  
  596. long long solveDigitDP(int pos, int sum, int tight, int S) {
  597. if (pos == (int)numStr.size()) return sum == S;
  598. long long &ret = dpDigit[pos][sum][tight];
  599. if (ret != -1) return ret;
  600. ret = 0;
  601. int limit = tight ? numStr[pos] - '0' : 9;
  602. for (int d = 0; d <= limit; d++) {
  603. ret += solveDigitDP(pos + 1, sum + d, tight && (d == limit), S);
  604. }
  605. return ret;
  606. }
  607.  
  608. long long countDigitSum(long long N, int S) {
  609. numStr = to_string(N);
  610. memset(dpDigit, -1, sizeof(dpDigit));
  611. return solveDigitDP(0, 0, 1, S);
  612. }
  613.  
  614. // Variant with leading zeros and counting a specific digit (e.g., digit 1)
  615. long long memoLead[20][20][2][2]; // [pos][cnt][tight][started]
  616.  
  617. long long solveDigitDPWithLeadingZero(int pos, int cnt, bool tight, bool started, int target, const string& num) {
  618. if (pos == (int)num.size()) return (started && cnt == target) ? 1 : 0;
  619. long long &ret = memoLead[pos][cnt][tight][started];
  620. if (ret != -1) return ret;
  621. ret = 0;
  622. int limit = tight ? num[pos] - '0' : 9;
  623. for (int d = 0; d <= limit; d++) {
  624. bool ntight = tight && (d == limit);
  625. bool nstarted = started || (d != 0);
  626. int add = (d == 1 && nstarted) ? 1 : 0;
  627. ret += solveDigitDPWithLeadingZero(pos + 1, cnt + add, ntight, nstarted, target, num);
  628. }
  629. return ret;
  630. }
  631.  
  632. long long countDigitSumWithLeadingZero(long long N, int target) {
  633. string s = to_string(N);
  634. memset(memoLead, -1, sizeof(memoLead));
  635. return solveDigitDPWithLeadingZero(0, 0, true, false, target, s);
  636. }
  637.  
  638. // --------------------------------------------
  639. // 14) DP with Prefix Sum Optimization
  640. // --------------------------------------------
  641. /*
  642.  * Optimizes DP transitions by using prefix sums to reduce time from O(K*n*limit) to O(K*n).
  643.  * - dpPrefixOpt: counts ways to reach sum n using exactly K moves, each move adds 1..limit.
  644.  * Complexity O(K*n), space O(n).
  645.  */
  646.  
  647. long long dpPrefixOpt(int n, int K, int limit) {
  648. vector<long long> dp(n + 1, 0), pref(n + 1, 0);
  649. dp[0] = 1;
  650. for (int step = 0; step < K; step++) {
  651. for (int i = 1; i <= n; i++) pref[i] = (pref[i - 1] + dp[i]) % MOD;
  652. vector<long long> ndp(n + 1, 0);
  653. for (int i = 1; i <= n; i++) {
  654. int l = max(0, i - limit);
  655. ndp[i] = (pref[i - 1] - (l > 0 ? pref[l - 1] : 0) + MOD) % MOD;
  656. }
  657. dp = ndp;
  658. }
  659. long long ans = 0;
  660. for (int i = 0; i <= n; i++) ans = (ans + dp[i]) % MOD;
  661. return ans;
  662. }
  663.  
  664. // --------------------------------------------
  665. // 15) DP + Sliding Window / Monotonic Queue
  666. // --------------------------------------------
  667. /*
  668.  * Monotonic queue optimization for DP with sliding window maximum.
  669.  * - maxSumWithWindow: example (may need verification; provided as template).
  670.  * Usually used for problems like "max sum of subsequence with gap constraint".
  671.  * Complexity O(n).
  672.  */
  673.  
  674. long long maxSumWithWindow(const vector<long long>& arr, int K) {
  675. int n = arr.size();
  676. vector<long long> dp(n + 1, 0);
  677. deque<int> dq;
  678. for (int i = 1; i <= n; i++) {
  679. if (!dq.empty() && dq.front() < i - K) dq.pop_front();
  680. dp[i] = dp[i - 1] + arr[i - 1];
  681. if (!dq.empty()) dp[i] = max(dp[i], dp[dq.front()] + arr[i - 1]);
  682. while (!dq.empty() && dp[dq.back()] <= dp[i]) dq.pop_back();
  683. dq.push_back(i);
  684. }
  685. return dp[n];
  686. }
  687.  
  688. // --------------------------------------------
  689. // 16) DP + Bitmask Subsets (SOS DP)
  690. // --------------------------------------------
  691. /*
  692.  * Sum Over Subsets DP (SOS DP) to compute f[mask] = sum_{sub ⊆ mask} a[sub].
  693.  * - sosDP: in-place transform, O(n * 2^n) time, O(2^n) space.
  694.  * Used for subset convolution and related problems.
  695.  */
  696.  
  697. vector<int> sosDP(const vector<int>& a) {
  698. int n = a.size();
  699. int N = 1 << n;
  700. vector<int> f = a;
  701. for (int i = 0; i < n; i++) {
  702. for (int mask = 0; mask < N; mask++) {
  703. if (mask & (1 << i)) f[mask] += f[mask ^ (1 << i)];
  704. }
  705. }
  706. return f;
  707. }
  708.  
  709. // --------------------------------------------
  710. // 17) DP with Monotonic Stack (for histograms etc.)
  711. // --------------------------------------------
  712. /*
  713.  * Largest rectangle in histogram using monotonic stack.
  714.  * - largestRectangleArea: O(n) time, O(n) space.
  715.  */
  716.  
  717. long long largestRectangleArea(const vector<int>& heights) {
  718. int n = heights.size();
  719. vector<int> left(n), right(n);
  720. stack<int> st;
  721. for (int i = 0; i < n; i++) {
  722. while (!st.empty() && heights[st.top()] >= heights[i]) st.pop();
  723. left[i] = st.empty() ? -1 : st.top();
  724. st.push(i);
  725. }
  726. while (!st.empty()) st.pop();
  727. for (int i = n - 1; i >= 0; i--) {
  728. while (!st.empty() && heights[st.top()] >= heights[i]) st.pop();
  729. right[i] = st.empty() ? n : st.top();
  730. st.push(i);
  731. }
  732. long long ans = 0;
  733. for (int i = 0; i < n; i++) {
  734. ans = max(ans, 1LL * heights[i] * (right[i] - left[i] - 1));
  735. }
  736. return ans;
  737. }
  738.  
  739. // --------------------------------------------
  740. // 18) DP + Combinatorics (NCR, precomputation)
  741. // --------------------------------------------
  742. /*
  743.  * Precomputation of factorials and inverse factorials for nCr modulo MOD.
  744.  * - initComb(): must be called once before using nCr.
  745.  * - nCr(n,r): returns C(n,r) mod MOD in O(1).
  746.  * MOD must be prime.
  747.  */
  748.  
  749. const int MAXC = 1000005;
  750. long long fact[MAXC], invFact[MAXC];
  751.  
  752. long long modPow(long long a, long long e) {
  753. long long r = 1;
  754. while (e) {
  755. if (e & 1) r = (r * a) % MOD;
  756. a = (a * a) % MOD;
  757. e >>= 1;
  758. }
  759. return r;
  760. }
  761.  
  762. void initComb() {
  763. fact[0] = 1;
  764. for (int i = 1; i < MAXC; i++) fact[i] = fact[i - 1] * i % MOD;
  765. invFact[MAXC - 1] = modPow(fact[MAXC - 1], MOD - 2);
  766. for (int i = MAXC - 2; i >= 0; i--) invFact[i] = invFact[i + 1] * (i + 1) % MOD;
  767. }
  768.  
  769. long long nCr(int n, int r) {
  770. if (r < 0 || r > n) return 0;
  771. return fact[n] * invFact[r] % MOD * invFact[n - r] % MOD;
  772. }
  773.  
  774. // --------------------------------------------
  775. // 19) DP for Longest Palindromic Subsequence
  776. // --------------------------------------------
  777. /*
  778.  * Longest Palindromic Subsequence (LPS) length.
  779.  * - LPS: interval DP, O(n^2) time and space.
  780.  */
  781.  
  782. int LPS(const string& s) {
  783. int n = s.size();
  784. vector<vector<int>> dp(n, vector<int>(n, 0));
  785. for (int i = 0; i < n; i++) dp[i][i] = 1;
  786. for (int len = 2; len <= n; len++) {
  787. for (int i = 0; i <= n - len; i++) {
  788. int j = i + len - 1;
  789. if (s[i] == s[j]) dp[i][j] = dp[i + 1][j - 1] + 2;
  790. else dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
  791. }
  792. }
  793. return dp[0][n - 1];
  794. }
  795.  
  796. // --------------------------------------------
  797. // 20) DP for Longest Common Substring (LCSubstr)
  798. // --------------------------------------------
  799. /*
  800.  * Longest common substring (contiguous) between two strings.
  801.  * - longestCommonSubstring: O(n*m) time and space.
  802.  */
  803.  
  804. int longestCommonSubstring(const string& a, const string& b) {
  805. int n = a.size(), m = b.size();
  806. vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
  807. int ans = 0;
  808. for (int i = 1; i <= n; i++) {
  809. for (int j = 1; j <= m; j++) {
  810. if (a[i - 1] == b[j - 1]) {
  811. dp[i][j] = dp[i - 1][j - 1] + 1;
  812. ans = max(ans, dp[i][j]);
  813. }
  814. }
  815. }
  816. return ans;
  817. }
  818.  
  819. // --------------------------------------------
  820. // 21) DP with Rolling Array (Space Optimization)
  821. // --------------------------------------------
  822. /*
  823.  * Space-optimized iterative Fibonacci.
  824.  * - fibOptimized: O(1) space, O(n) time.
  825.  */
  826.  
  827. long long fibOptimized(int n) {
  828. if (n <= 1) return n;
  829. long long a = 0, b = 1;
  830. for (int i = 2; i <= n; i++) {
  831. long long c = a + b;
  832. a = b;
  833. b = c;
  834. }
  835. return b;
  836. }
  837.  
  838. // --------------------------------------------
  839. // 22) DP for Partition Problems
  840. // --------------------------------------------
  841. /*
  842.  * Partition into two subsets with equal sum.
  843.  * - canPartition: O(n * target) time, O(target) space.
  844.  */
  845.  
  846. bool canPartition(const vector<int>& nums) {
  847. int sum = accumulate(nums.begin(), nums.end(), 0);
  848. if (sum & 1) return false;
  849. int target = sum / 2;
  850. vector<bool> dp(target + 1, false);
  851. dp[0] = true;
  852. for (int x : nums) {
  853. for (int s = target; s >= x; s--) {
  854. if (dp[s - x]) dp[s] = true;
  855. }
  856. }
  857. return dp[target];
  858. }
  859.  
  860. // --------------------------------------------
  861. // 23) DP + Divide and Conquer Optimization
  862. // --------------------------------------------
  863. /*
  864.  * Divide and Conquer DP optimization for DP of the form:
  865.  * dp[i][j] = min_{k < j} (dp[i-1][k] + cost(k, j))
  866.  * when the optimal split point is monotonic.
  867.  * - compute: template function; adapt cost function accordingly.
  868.  * Complexity O(m * n log n) for each row.
  869.  */
  870.  
  871. void computeDC(int l, int r, int optL, int optR, int k, vector<vector<long long>>& dp, const vector<long long>& pref) {
  872. if (l > r) return;
  873. int mid = (l + r) / 2;
  874. int bestOpt = optL;
  875. long long bestVal = LLONG_MAX;
  876. for (int i = optL; i <= min(optR, mid - 1); i++) {
  877. long long cost = dp[k - 1][i] + (pref[mid] - pref[i]) * (pref[mid] - pref[i]); // example cost
  878. if (cost < bestVal) {
  879. bestVal = cost;
  880. bestOpt = i;
  881. }
  882. }
  883. dp[k][mid] = bestVal;
  884. computeDC(l, mid - 1, optL, bestOpt, k, dp, pref);
  885. computeDC(mid + 1, r, bestOpt, optR, k, dp, pref);
  886. }
  887.  
  888. // --------------------------------------------
  889. // 24) DP + Knuth Optimization (mentioned)
  890. // --------------------------------------------
  891. // Knuth optimization can be applied when quadrangle inequality holds.
  892. // Not implemented as a separate function.
  893.  
  894. // --------------------------------------------
  895. // 25) DP + Bitmask (Counting subsets with sum)
  896. // --------------------------------------------
  897. /*
  898.  * Count subsets with a given sum (0/1 knapsack counting).
  899.  * - countSubsetsWithSum: O(n * target), O(target).
  900.  */
  901.  
  902. long long countSubsetsWithSum(const vector<int>& arr, int target) {
  903. int n = arr.size();
  904. vector<long long> dp(target + 1, 0);
  905. dp[0] = 1;
  906. for (int x : arr) {
  907. for (int s = target; s >= x; s--) {
  908. dp[s] += dp[s - x];
  909. }
  910. }
  911. return dp[target];
  912. }
  913.  
  914. // --------------------------------------------
  915. // 26) DP + Meet-in-the-Middle (for large N up to 40)
  916. // --------------------------------------------
  917. /*
  918.  * Meet-in-the-Middle for subset sum problems when n ≤ 40.
  919.  * - getSubsetSums: generates all subset sums of a half-array.
  920.  * - countSubsetsWithSumMITM: counts subsets with exact target.
  921.  * Complexity O(2^(n/2) log 2^(n/2)).
  922.  */
  923.  
  924. vector<long long> getSubsetSums(const vector<int>& arr) {
  925. vector<long long> sums;
  926. int n = arr.size();
  927. for (int mask = 0; mask < (1 << n); mask++) {
  928. long long sum = 0;
  929. for (int i = 0; i < n; i++) {
  930. if (mask & (1 << i)) sum += arr[i];
  931. }
  932. sums.push_back(sum);
  933. }
  934. return sums;
  935. }
  936.  
  937. long long countSubsetsWithSumMITM(const vector<int>& arr, int target) {
  938. int n = arr.size();
  939. vector<int> left(arr.begin(), arr.begin() + n / 2);
  940. vector<int> right(arr.begin() + n / 2, arr.end());
  941. vector<long long> L = getSubsetSums(left), R = getSubsetSums(right);
  942. sort(R.begin(), R.end());
  943. long long ans = 0;
  944. for (long long s : L) {
  945. ans += upper_bound(R.begin(), R.end(), target - s) - lower_bound(R.begin(), R.end(), target - s);
  946. }
  947. return ans;
  948. }
  949.  
  950. // --------------------------------------------
  951. // 27) DP + Matrix Exponentiation (for linear recurrences)
  952. // --------------------------------------------
  953. /*
  954.  * Matrix exponentiation for linear recurrences.
  955.  * - Matrix struct for n x n matrices with multiplication modulo MOD.
  956.  * - matPow: exponentiation.
  957.  * - fibMatrix: Fibonacci using matrix exponentiation O(log n).
  958.  * - linearRecurrence: computes n-th term of a 2nd order recurrence.
  959.  */
  960.  
  961. struct Matrix {
  962. vector<vector<long long>> mat;
  963. int n;
  964. Matrix(int n, bool identity = false) : n(n), mat(n, vector<long long>(n, 0)) {
  965. if (identity) for (int i = 0; i < n; i++) mat[i][i] = 1;
  966. }
  967. Matrix operator*(const Matrix& other) const {
  968. Matrix res(n);
  969. for (int i = 0; i < n; i++) {
  970. for (int k = 0; k < n; k++) {
  971. if (mat[i][k] == 0) continue;
  972. for (int j = 0; j < n; j++) {
  973. res.mat[i][j] = (res.mat[i][j] + mat[i][k] * other.mat[k][j]) % MOD;
  974. }
  975. }
  976. }
  977. return res;
  978. }
  979. };
  980.  
  981. Matrix matPow(Matrix base, long long exp) {
  982. Matrix res(base.n, true);
  983. while (exp > 0) {
  984. if (exp & 1) res = res * base;
  985. base = base * base;
  986. exp >>= 1;
  987. }
  988. return res;
  989. }
  990.  
  991. long long fibMatrix(int n) {
  992. if (n <= 1) return n;
  993. Matrix base(2);
  994. base.mat = {{1, 1}, {1, 0}};
  995. Matrix res = matPow(base, n - 1);
  996. return res.mat[0][0];
  997. }
  998.  
  999. long long linearRecurrence(long long n, long long a, long long b, long long f0, long long f1) {
  1000. if (n == 0) return f0;
  1001. if (n == 1) return f1;
  1002. Matrix base(2);
  1003. base.mat = {{a, b}, {1, 0}};
  1004. Matrix res = matPow(base, n - 1);
  1005. return (res.mat[0][0] * f1 + res.mat[0][1] * f0) % MOD;
  1006. }
  1007.  
  1008. // --------------------------------------------
  1009. // 28) DP for "Minimum Operations" (like min steps to reduce to 1)
  1010. // --------------------------------------------
  1011. /*
  1012.  * Minimum steps to reduce n to 1 using operations: subtract 1, divide by 2 (if even), divide by 3 (if divisible by 3).
  1013.  * - minStepsToOne: O(n) time and space.
  1014.  */
  1015.  
  1016. int minStepsToOne(int n) {
  1017. vector<int> dp(n + 1, 1e9);
  1018. dp[1] = 0;
  1019. for (int i = 2; i <= n; i++) {
  1020. dp[i] = dp[i - 1] + 1;
  1021. if (i % 2 == 0) dp[i] = min(dp[i], dp[i / 2] + 1);
  1022. if (i % 3 == 0) dp[i] = min(dp[i], dp[i / 3] + 1);
  1023. }
  1024. return dp[n];
  1025. }
  1026.  
  1027. // --------------------------------------------
  1028. // 29) DP for "Jump Game" / "Minimum Jumps to Reach End"
  1029. // --------------------------------------------
  1030. /*
  1031.  * Minimum number of jumps to reach the end.
  1032.  * - minJumps: O(n^2) DP (for small n).
  1033.  * - minJumpsGreedy: O(n) greedy for reachable arrays.
  1034.  */
  1035.  
  1036. int minJumps(const vector<int>& nums) {
  1037. int n = nums.size();
  1038. vector<int> dp(n, INT_MAX);
  1039. dp[0] = 0;
  1040. for (int i = 0; i < n; i++) {
  1041. if (dp[i] == INT_MAX) continue;
  1042. for (int j = i + 1; j <= min(n - 1, i + nums[i]); j++) {
  1043. dp[j] = min(dp[j], dp[i] + 1);
  1044. }
  1045. }
  1046. return dp[n - 1];
  1047. }
  1048.  
  1049. int minJumpsGreedy(const vector<int>& nums) {
  1050. int n = nums.size();
  1051. if (n <= 1) return 0;
  1052. int jumps = 0, currEnd = 0, farthest = 0;
  1053. for (int i = 0; i < n - 1; i++) {
  1054. farthest = max(farthest, i + nums[i]);
  1055. if (i == currEnd) {
  1056. jumps++;
  1057. currEnd = farthest;
  1058. }
  1059. }
  1060. return jumps;
  1061. }
  1062.  
  1063. // --------------------------------------------
  1064. // 30) DP for "Word Break" (Can be segmented)
  1065. // --------------------------------------------
  1066. /*
  1067.  * Determines if a string can be segmented into dictionary words.
  1068.  * - wordBreak: O(n^2) time with hash set.
  1069.  */
  1070.  
  1071. bool wordBreak(const string& s, const vector<string>& wordDict) {
  1072. unordered_set<string> dict(wordDict.begin(), wordDict.end());
  1073. int n = s.size();
  1074. vector<bool> dp(n + 1, false);
  1075. dp[0] = true;
  1076. for (int i = 1; i <= n; i++) {
  1077. for (int j = 0; j < i; j++) {
  1078. if (dp[j] && dict.count(s.substr(j, i - j))) {
  1079. dp[i] = true;
  1080. break;
  1081. }
  1082. }
  1083. }
  1084. return dp[n];
  1085. }
  1086.  
  1087. // --------------------------------------------
  1088. // 31) DP for "Number of Ways to Decode" (Leetcode 91)
  1089. // --------------------------------------------
  1090. /*
  1091.  * Counts ways to decode a digit string (A=1,...,Z=26).
  1092.  * - numDecodings: O(n) time and space.
  1093.  */
  1094.  
  1095. int numDecodings(const string& s) {
  1096. int n = s.size();
  1097. vector<long long> dp(n + 1, 0);
  1098. dp[0] = 1;
  1099. for (int i = 1; i <= n; i++) {
  1100. if (s[i - 1] != '0') dp[i] += dp[i - 1];
  1101. if (i >= 2) {
  1102. int two = (s[i - 2] - '0') * 10 + (s[i - 1] - '0');
  1103. if (two >= 10 && two <= 26) dp[i] += dp[i - 2];
  1104. }
  1105. }
  1106. return dp[n];
  1107. }
  1108.  
  1109. // --------------------------------------------
  1110. // 32) DP + KMP Automaton (for avoiding patterns)
  1111. // --------------------------------------------
  1112. /*
  1113.  * Count strings of length n over lowercase letters that do NOT contain a given pattern.
  1114.  * - buildKMPAutomaton: builds transition table.
  1115.  * - countStringsWithoutPattern: DP using automaton.
  1116.  * Complexity O(n * m * 26).
  1117.  */
  1118.  
  1119. vector<array<int, 26>> buildKMPAutomaton(const string& pat) {
  1120. int m = pat.size();
  1121. vector<array<int, 26>> aut(m + 1);
  1122. vector<int> pi(m, 0);
  1123. for (int i = 1; i < m; i++) {
  1124. int j = pi[i - 1];
  1125. while (j > 0 && pat[i] != pat[j]) j = pi[j - 1];
  1126. if (pat[i] == pat[j]) j++;
  1127. pi[i] = j;
  1128. }
  1129. for (int i = 0; i <= m; i++) {
  1130. for (int c = 0; c < 26; c++) {
  1131. if (i < m && pat[i] == 'a' + c) aut[i][c] = i + 1;
  1132. else if (i == 0) aut[i][c] = 0;
  1133. else aut[i][c] = aut[pi[i - 1]][c];
  1134. }
  1135. }
  1136. return aut;
  1137. }
  1138.  
  1139. long long countStringsWithoutPattern(int n, const string& pat, long long MOD) {
  1140. auto aut = buildKMPAutomaton(pat);
  1141. int m = pat.size();
  1142. vector<vector<long long>> dp(n + 1, vector<long long>(m + 1, 0));
  1143. dp[0][0] = 1;
  1144. for (int i = 0; i < n; i++) {
  1145. for (int state = 0; state < m; state++) {
  1146. for (int c = 0; c < 26; c++) {
  1147. int nxt = aut[state][c];
  1148. if (nxt == m) continue;
  1149. dp[i + 1][nxt] = (dp[i + 1][nxt] + dp[i][state]) % MOD;
  1150. }
  1151. }
  1152. }
  1153. long long ans = 0;
  1154. for (int state = 0; state < m; state++) ans = (ans + dp[n][state]) % MOD;
  1155. return ans;
  1156. }
  1157.  
  1158. // --------------------------------------------
  1159. // 33) DP for "Distinct Subsequences"
  1160. // --------------------------------------------
  1161. /*
  1162.  * Count number of distinct subsequences (including empty) of a string.
  1163.  * - distinctSubsequences: O(n) time and space (using last occurrence).
  1164.  * Returns total distinct subsequences minus 1 (excluding empty).
  1165.  */
  1166.  
  1167. int distinctSubsequences(const string& s) {
  1168. int n = s.size();
  1169. vector<long long> dp(n + 1, 0);
  1170. dp[0] = 1;
  1171. vector<int> last(26, -1);
  1172. for (int i = 1; i <= n; i++) {
  1173. dp[i] = (2 * dp[i - 1]) % MOD;
  1174. int c = s[i - 1] - 'a';
  1175. if (last[c] != -1) dp[i] = (dp[i] - dp[last[c] - 1] + MOD) % MOD;
  1176. last[c] = i;
  1177. }
  1178. return dp[n] - 1; // exclude empty
  1179. }
  1180.  
  1181. // --------------------------------------------
  1182. // 34) DP for "Minimum Path Cover in DAG" (not implemented)
  1183. // --------------------------------------------
  1184. // (See bipartite matching for DAG path cover.)
  1185.  
  1186. // --------------------------------------------
  1187. // 35) DP + Topological Sort (DAG DP)
  1188. // --------------------------------------------
  1189. /*
  1190.  * Longest path in a weighted DAG.
  1191.  * - topologicalSort: computes topological order.
  1192.  * - dagLongestPath: returns maximum path sum (vertex weights).
  1193.  * Complexity O(V + E).
  1194.  */
  1195.  
  1196. vector<int> topo;
  1197.  
  1198. void topologicalSort(int n, vector<vector<int>>& adj) {
  1199. vector<int> indeg(n, 0);
  1200. for (int u = 0; u < n; u++) for (int v : adj[u]) indeg[v]++;
  1201. queue<int> q;
  1202. for (int i = 0; i < n; i++) if (indeg[i] == 0) q.push(i);
  1203. while (!q.empty()) {
  1204. int u = q.front(); q.pop();
  1205. topo.push_back(u);
  1206. for (int v : adj[u]) {
  1207. if (--indeg[v] == 0) q.push(v);
  1208. }
  1209. }
  1210. }
  1211.  
  1212. long long dagLongestPath(int n, vector<vector<int>>& adj, vector<int>& weight) {
  1213. topologicalSort(n, adj);
  1214. vector<long long> dp(n, 0);
  1215. for (int u : topo) {
  1216. for (int v : adj[u]) {
  1217. dp[v] = max(dp[v], dp[u] + weight[v]);
  1218. }
  1219. }
  1220. return *max_element(dp.begin(), dp.end());
  1221. }
  1222.  
  1223. // --------------------------------------------
  1224. // 36) DP + Game Theory (optimal play)
  1225. // --------------------------------------------
  1226. /*
  1227.  * Predict the winner in a game where players pick from ends.
  1228.  * - predictTheWinner: returns true if first player can win.
  1229.  * O(n^2) time and space.
  1230.  */
  1231.  
  1232. bool predictTheWinner(vector<int>& nums) {
  1233. int n = nums.size();
  1234. vector<vector<int>> dp(n, vector<int>(n, 0));
  1235. for (int i = 0; i < n; i++) dp[i][i] = nums[i];
  1236. for (int len = 2; len <= n; len++) {
  1237. for (int i = 0; i <= n - len; i++) {
  1238. int j = i + len - 1;
  1239. dp[i][j] = max(nums[i] - dp[i + 1][j], nums[j] - dp[i][j - 1]);
  1240. }
  1241. }
  1242. return dp[0][n - 1] >= 0;
  1243. }
  1244.  
  1245. // --------------------------------------------
  1246. // 37) DP + "Maximum Sum Rectangle in 2D" (Kadane on rows)
  1247. // --------------------------------------------
  1248. /*
  1249.  * Maximum sum sub-rectangle in a 2D matrix.
  1250.  * - maxSumRectangle: O(n^2 * m) time, O(m) space.
  1251.  * Works for both int and long long matrices (overloaded).
  1252.  */
  1253.  
  1254. long long maxSumRectangle(const vector<vector<int>>& mat) {
  1255. int n = mat.size(), m = mat[0].size();
  1256. long long best = LLONG_MIN;
  1257. for (int top = 0; top < n; top++) {
  1258. vector<long long> col(m, 0);
  1259. for (int bottom = top; bottom < n; bottom++) {
  1260. for (int j = 0; j < m; j++) col[j] += mat[bottom][j];
  1261. long long cur = 0, mx = LLONG_MIN;
  1262. for (int j = 0; j < m; j++) {
  1263. cur = max(col[j], cur + col[j]);
  1264. mx = max(mx, cur);
  1265. }
  1266. best = max(best, mx);
  1267. }
  1268. }
  1269. return best;
  1270. }
  1271.  
  1272. // Overload for long long matrix
  1273. long long maxSumRectangle(const vector<vector<long long>>& matrix) {
  1274. int n = matrix.size(), m = matrix[0].size();
  1275. long long ans = LLONG_MIN;
  1276. for (int top = 0; top < n; top++) {
  1277. vector<long long> colSum(m, 0);
  1278. for (int bottom = top; bottom < n; bottom++) {
  1279. for (int j = 0; j < m; j++) colSum[j] += matrix[bottom][j];
  1280. long long maxEnd = 0, maxSum = LLONG_MIN;
  1281. for (int j = 0; j < m; j++) {
  1282. maxEnd = max(colSum[j], maxEnd + colSum[j]);
  1283. maxSum = max(maxSum, maxEnd);
  1284. }
  1285. ans = max(ans, maxSum);
  1286. }
  1287. }
  1288. return ans;
  1289. }
  1290.  
  1291. // --------------------------------------------
  1292. // 38) DP + Catalan Numbers
  1293. // --------------------------------------------
  1294. /*
  1295.  * Compute n-th Catalan number using DP.
  1296.  * - catalan: O(n^2) time, O(n) space.
  1297.  * Catalan numbers grow fast; use long long for n ≤ 30.
  1298.  */
  1299.  
  1300. long long catalan(int n) {
  1301. vector<long long> cat(n + 1, 0);
  1302. cat[0] = 1;
  1303. for (int i = 1; i <= n; i++) {
  1304. for (int j = 0; j < i; j++) {
  1305. cat[i] += cat[j] * cat[i - j - 1];
  1306. }
  1307. }
  1308. return cat[n];
  1309. }
  1310.  
  1311. // --------------------------------------------
  1312. // 39) DP for "Partition into K subarrays with min/max sum"
  1313. // --------------------------------------------
  1314. /*
  1315.  * Split array into k subarrays to minimize the maximum subarray sum.
  1316.  * - canPartitionKSubarrays: greedy check for a given target.
  1317.  * - splitArrayMinLargestSum: binary search on answer.
  1318.  * Complexity O(n log sum).
  1319.  */
  1320.  
  1321. bool canPartitionKSubarrays(const vector<int>& nums, int k, long long target) {
  1322. int cnt = 1;
  1323. long long sum = 0;
  1324. for (int x : nums) {
  1325. if (sum + x > target) {
  1326. cnt++;
  1327. sum = x;
  1328. } else sum += x;
  1329. }
  1330. return cnt <= k;
  1331. }
  1332.  
  1333. long long splitArrayMinLargestSum(const vector<int>& nums, int k) {
  1334. long long lo = *max_element(nums.begin(), nums.end());
  1335. long long hi = accumulate(nums.begin(), nums.end(), 0LL);
  1336. long long ans = hi;
  1337. while (lo <= hi) {
  1338. long long mid = (lo + hi) / 2;
  1339. if (canPartitionKSubarrays(nums, k, mid)) {
  1340. ans = mid;
  1341. hi = mid - 1;
  1342. } else lo = mid + 1;
  1343. }
  1344. return ans;
  1345. }
  1346.  
  1347. // --------------------------------------------
  1348. // 40) DP + BFS/Shortest Path (count ways)
  1349. // --------------------------------------------
  1350. /*
  1351.  * Counting ways in grid using BFS/DP (same as countPaths).
  1352.  * - countWaysInGridWithBFS: just an alias.
  1353.  */
  1354.  
  1355. long long countWaysInGridWithBFS(int n, int m) {
  1356. vector<vector<long long>> dp(n, vector<long long>(m, 0));
  1357. dp[0][0] = 1;
  1358. for (int i = 0; i < n; i++) {
  1359. for (int j = 0; j < m; j++) {
  1360. if (i > 0) dp[i][j] += dp[i - 1][j];
  1361. if (j > 0) dp[i][j] += dp[i][j - 1];
  1362. }
  1363. }
  1364. return dp[n - 1][m - 1];
  1365. }
  1366.  
  1367. // --------------------------------------------
  1368. // 41) DP + Floyd-Warshall (all-pairs shortest paths)
  1369. // --------------------------------------------
  1370. /*
  1371.  * All-pairs shortest paths in a graph (negative weights allowed, no negative cycles).
  1372.  * - floydWarshall: O(n^3) time, O(n^2) space.
  1373.  * Modifies dist matrix in-place.
  1374.  */
  1375.  
  1376. void floydWarshall(vector<vector<long long>>& dist) {
  1377. int n = dist.size();
  1378. for (int k = 0; k < n; k++) {
  1379. for (int i = 0; i < n; i++) {
  1380. for (int j = 0; j < n; j++) {
  1381. if (dist[i][k] != LLONG_MAX && dist[k][j] != LLONG_MAX) {
  1382. dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
  1383. }
  1384. }
  1385. }
  1386. }
  1387. }
  1388.  
  1389. // --------------------------------------------
  1390. // 42) DP + Bellman-Ford (shortest path with negative weights)
  1391. // --------------------------------------------
  1392. /*
  1393.  * Bellman-Ford for single-source shortest paths with negative edges.
  1394.  * - bellmanFord: O(VE) time, O(V) space.
  1395.  * Returns distances or empty vector if negative cycle detected.
  1396.  */
  1397.  
  1398. vector<long long> bellmanFord(int n, vector<tuple<int,int,long long>>& edges, int src) {
  1399. vector<long long> dist(n, LLONG_MAX);
  1400. dist[src] = 0;
  1401. for (int i = 0; i < n - 1; i++) {
  1402. for (auto [u, v, w] : edges) {
  1403. if (dist[u] != LLONG_MAX && dist[u] + w < dist[v]) {
  1404. dist[v] = dist[u] + w;
  1405. }
  1406. }
  1407. }
  1408. for (auto [u, v, w] : edges) {
  1409. if (dist[u] != LLONG_MAX && dist[u] + w < dist[v]) {
  1410. return {};
  1411. }
  1412. }
  1413. return dist;
  1414. }
  1415.  
  1416. // --------------------------------------------
  1417. // 43) DP + Grundy Numbers (impartial games)
  1418. // --------------------------------------------
  1419. /*
  1420.  * Compute Grundy numbers for combinatorial games.
  1421.  * - mex: minimum excluded value.
  1422.  * - grundy: for a single pile with given moves.
  1423.  * - grundyNumber: XOR of Grundy numbers for multiple piles.
  1424.  */
  1425.  
  1426. int mex(const vector<int>& v) {
  1427. vector<bool> vis(v.size() + 1, false);
  1428. for (int x : v) if (x < (int)vis.size()) vis[x] = true;
  1429. for (int i = 0; i < (int)vis.size(); i++) if (!vis[i]) return i;
  1430. return v.size();
  1431. }
  1432.  
  1433. int grundy(int n, vector<int>& moves) {
  1434. vector<int> g(n + 1, 0);
  1435. for (int i = 1; i <= n; i++) {
  1436. vector<int> reachable;
  1437. for (int m : moves) {
  1438. if (i >= m) reachable.push_back(g[i - m]);
  1439. }
  1440. g[i] = mex(reachable);
  1441. }
  1442. return g[n];
  1443. }
  1444.  
  1445. int grundyNumber(int piles[], int n, int maxMove) {
  1446. vector<int> g(maxMove + 1, 0);
  1447. for (int i = 1; i <= maxMove; i++) {
  1448. vector<int> reachable;
  1449. for (int move = 1; move <= i; move++) {
  1450. reachable.push_back(g[i - move]);
  1451. }
  1452. g[i] = mex(reachable);
  1453. }
  1454. int xr = 0;
  1455. for (int i = 0; i < n; i++) xr ^= g[piles[i]];
  1456. return xr; // zero means losing
  1457. }
  1458.  
  1459. // --------------------------------------------
  1460. // 44) DP + Convex Hull Trick (CHT)
  1461. // --------------------------------------------
  1462. /*
  1463.  * Convex Hull Trick for DP optimization with linear functions.
  1464.  * Slopes must be monotonic. Supports min queries.
  1465.  * - Line: y = m*x + c.
  1466.  * - CHT: add lines (monotonic slopes), query min at x.
  1467.  * Use when DP transition is dp[i] = min_j (dp[j] + m_j * x_i + c_j).
  1468.  */
  1469.  
  1470. struct Line {
  1471. long long m, c;
  1472. long long eval(long long x) { return m * x + c; }
  1473. };
  1474.  
  1475. struct CHT {
  1476. vector<Line> lines;
  1477. int ptr = 0;
  1478. bool bad(Line l1, Line l2, Line l3) {
  1479. return (l3.c - l1.c) * (l1.m - l2.m) <= (l2.c - l1.c) * (l1.m - l3.m);
  1480. }
  1481. void addLine(Line l) {
  1482. while (lines.size() >= 2 && bad(lines[lines.size()-2], lines.back(), l))
  1483. lines.pop_back();
  1484. lines.push_back(l);
  1485. }
  1486. long long query(long long x) {
  1487. while (ptr + 1 < lines.size() && lines[ptr+1].eval(x) <= lines[ptr].eval(x))
  1488. ptr++;
  1489. return lines[ptr].eval(x);
  1490. }
  1491. };
  1492.  
  1493. // --------------------------------------------
  1494. // 45) DP + Li Chao Tree (for min/max queries)
  1495. // --------------------------------------------
  1496. /*
  1497.  * Li Chao Tree for dynamic addition of lines and min/max queries over arbitrary x.
  1498.  * Supports discrete x-coordinates.
  1499.  * - LiChao: addLine, query.
  1500.  */
  1501.  
  1502. struct LiChao {
  1503. struct Node {
  1504. Line line;
  1505. Node *left, *right;
  1506. Node(Line l) : line(l), left(nullptr), right(nullptr) {}
  1507. };
  1508. Node* root;
  1509. long long xL, xR;
  1510. LiChao(long long l, long long r) : xL(l), xR(r), root(nullptr) {}
  1511. void addLine(Line nw) { root = addLine(root, xL, xR, nw); }
  1512. Node* addLine(Node* node, long long l, long long r, Line nw) {
  1513. if (!node) return new Node(nw);
  1514. long long mid = (l + r) / 2;
  1515. Line lo = node->line, hi = nw;
  1516. if (lo.eval(mid) > hi.eval(mid)) swap(node->line, nw);
  1517. if (l == r) return node;
  1518. if (nw.eval(l) < node->line.eval(l))
  1519. node->left = addLine(node->left, l, mid, nw);
  1520. else if (nw.eval(r) < node->line.eval(r))
  1521. node->right = addLine(node->right, mid+1, r, nw);
  1522. return node;
  1523. }
  1524. long long query(long long x) { return query(root, xL, xR, x); }
  1525. long long query(Node* node, long long l, long long r, long long x) {
  1526. if (!node) return LLONG_MAX;
  1527. long long res = node->line.eval(x);
  1528. if (l == r) return res;
  1529. long long mid = (l + r) / 2;
  1530. if (x <= mid) return min(res, query(node->left, l, mid, x));
  1531. else return min(res, query(node->right, mid+1, r, x));
  1532. }
  1533. };
  1534.  
  1535. // --------------------------------------------
  1536. // 46) DP + Alien Trick (Lagrangian relaxation)
  1537. // --------------------------------------------
  1538. /*
  1539.  * Alien trick to solve DP with exactly K items.
  1540.  * - solveWithPenalty: DP with penalty added per item.
  1541.  * - solveWithExactlyK: binary search on penalty.
  1542.  * Requires the DP to be convex.
  1543.  * Placeholder implementation; fill with actual DP.
  1544.  */
  1545.  
  1546. pair<long long, int> solveWithPenalty(int penalty) {
  1547. // Placeholder: should return {max value, number of items}
  1548. return {0, 0};
  1549. }
  1550.  
  1551. long long solveWithExactlyK(int k) {
  1552. long long lo = -1e9, hi = 1e9, ans = 0;
  1553. while (lo <= hi) {
  1554. long long mid = (lo + hi) / 2;
  1555. auto [val, cnt] = solveWithPenalty(mid);
  1556. if (cnt >= k) {
  1557. ans = val + mid * k;
  1558. lo = mid + 1;
  1559. } else hi = mid - 1;
  1560. }
  1561. return ans;
  1562. }
  1563.  
  1564. // --------------------------------------------
  1565. // 47) DP + "Interval DP" (Burst Balloons, Palindrome cuts, etc.)
  1566. // --------------------------------------------
  1567. /*
  1568.  * Interval DP examples.
  1569.  * - maxCoinsBurstBalloons: Leetcode 312.
  1570.  * - minCutPalindrome: minimum cuts to partition into palindromes.
  1571.  * - longestValidParentheses: length of longest valid parentheses substring.
  1572.  */
  1573.  
  1574. int maxCoinsBurstBalloons(const vector<int>& nums) {
  1575. int n = nums.size();
  1576. vector<int> a(n + 2, 1);
  1577. for (int i = 1; i <= n; i++) a[i] = nums[i - 1];
  1578. vector<vector<int>> dp(n + 2, vector<int>(n + 2, 0));
  1579. for (int len = 1; len <= n; len++) {
  1580. for (int l = 1; l <= n - len + 1; l++) {
  1581. int r = l + len - 1;
  1582. for (int k = l; k <= r; k++) {
  1583. dp[l][r] = max(dp[l][r], dp[l][k - 1] + dp[k + 1][r] + a[l - 1] * a[k] * a[r + 1]);
  1584. }
  1585. }
  1586. }
  1587. return dp[1][n];
  1588. }
  1589.  
  1590. int minCutPalindrome(const string& s) {
  1591. int n = s.size();
  1592. vector<vector<bool>> isPal(n, vector<bool>(n, false));
  1593. for (int i = 0; i < n; i++) isPal[i][i] = true;
  1594. for (int len = 2; len <= n; len++) {
  1595. for (int i = 0; i <= n - len; i++) {
  1596. int j = i + len - 1;
  1597. if (s[i] == s[j] && (len == 2 || isPal[i + 1][j - 1])) {
  1598. isPal[i][j] = true;
  1599. }
  1600. }
  1601. }
  1602. vector<int> dp(n, INT_MAX);
  1603. for (int i = 0; i < n; i++) {
  1604. if (isPal[0][i]) dp[i] = 0;
  1605. else {
  1606. for (int j = 0; j < i; j++) {
  1607. if (isPal[j + 1][i] && dp[j] + 1 < dp[i]) {
  1608. dp[i] = dp[j] + 1;
  1609. }
  1610. }
  1611. }
  1612. }
  1613. return dp[n - 1];
  1614. }
  1615.  
  1616. int longestValidParentheses(const string& s) {
  1617. int n = s.size();
  1618. vector<int> dp(n, 0);
  1619. int ans = 0;
  1620. for (int i = 1; i < n; i++) {
  1621. if (s[i] == ')') {
  1622. if (s[i - 1] == '(') {
  1623. dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
  1624. } else if (i - dp[i - 1] - 1 >= 0 && s[i - dp[i - 1] - 1] == '(') {
  1625. dp[i] = dp[i - 1] + 2 + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0);
  1626. }
  1627. ans = max(ans, dp[i]);
  1628. }
  1629. }
  1630. return ans;
  1631. }
  1632.  
  1633. // --------------------------------------------
  1634. // 48) DP + "Ugly Numbers" (DP with prime factors)
  1635. // --------------------------------------------
  1636. /*
  1637.  * Find the n-th ugly number (factors only 2, 3, 5).
  1638.  * - nthUglyNumber: O(n) time, O(n) space.
  1639.  */
  1640.  
  1641. long long nthUglyNumber(int n) {
  1642. vector<long long> ugly(n);
  1643. ugly[0] = 1;
  1644. int p2 = 0, p3 = 0, p5 = 0;
  1645. for (int i = 1; i < n; i++) {
  1646. long long next2 = ugly[p2] * 2;
  1647. long long next3 = ugly[p3] * 3;
  1648. long long next5 = ugly[p5] * 5;
  1649. long long next = min({next2, next3, next5});
  1650. ugly[i] = next;
  1651. if (next == next2) p2++;
  1652. if (next == next3) p3++;
  1653. if (next == next5) p5++;
  1654. }
  1655. return ugly[n - 1];
  1656. }
  1657.  
  1658. // --------------------------------------------
  1659. // 49) DP + "Shortest Common Supersequence"
  1660. // --------------------------------------------
  1661. /*
  1662.  * Shortest string that contains both a and b as subsequences.
  1663.  * - shortestCommonSupersequence: O(n*m) time and space.
  1664.  */
  1665.  
  1666. string shortestCommonSupersequence(const string& a, const string& b) {
  1667. int n = a.size(), m = b.size();
  1668. vector<vector<int>> dp(n+1, vector<int>(m+1, 0));
  1669. for (int i = 0; i <= n; i++) dp[i][0] = i;
  1670. for (int j = 0; j <= m; j++) dp[0][j] = j;
  1671. for (int i = 1; i <= n; i++) {
  1672. for (int j = 1; j <= m; j++) {
  1673. if (a[i-1] == b[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
  1674. else dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + 1;
  1675. }
  1676. }
  1677. string res;
  1678. int i = n, j = m;
  1679. while (i > 0 || j > 0) {
  1680. if (i > 0 && j > 0 && a[i-1] == b[j-1]) {
  1681. res.push_back(a[i-1]); i--; j--;
  1682. } else if (i > 0 && (j == 0 || dp[i-1][j] <= dp[i][j-1])) {
  1683. res.push_back(a[i-1]); i--;
  1684. } else {
  1685. res.push_back(b[j-1]); j--;
  1686. }
  1687. }
  1688. reverse(res.begin(), res.end());
  1689. return res;
  1690. }
  1691.  
  1692. // --------------------------------------------
  1693. // 50) DP + Expected Steps in DAG
  1694. // --------------------------------------------
  1695. /*
  1696.  * Expected number of steps to reach goal in a probabilistic DAG.
  1697.  * - expectedSteps: assumes edges go forward, compute backwards.
  1698.  */
  1699.  
  1700. double expectedSteps(int n, vector<vector<double>>& trans) {
  1701. vector<double> dp(n, 0);
  1702. for (int u = n - 2; u >= 0; u--) {
  1703. double sum = 0;
  1704. for (int v = u + 1; v < n; v++) {
  1705. sum += trans[u][v] * (1 + dp[v]);
  1706. }
  1707. dp[u] = sum;
  1708. }
  1709. return dp[0];
  1710. }
  1711.  
  1712. // --------------------------------------------
  1713. // 51) DP + "Count Subsets with Sum ≤ Target" (MITM)
  1714. // --------------------------------------------
  1715. /*
  1716.  * Count subsets with sum ≤ target using meet-in-the-middle.
  1717.  * - countSubsetsWithSumLE: O(2^(n/2) log 2^(n/2)).
  1718.  */
  1719.  
  1720. long long countSubsetsWithSumLE(const vector<int>& arr, int target) {
  1721. int n = arr.size();
  1722. int n1 = n / 2, n2 = n - n1;
  1723. vector<int> L, R;
  1724. for (int mask = 0; mask < (1 << n1); mask++) {
  1725. int sum = 0;
  1726. for (int i = 0; i < n1; i++) if (mask & (1 << i)) sum += arr[i];
  1727. L.push_back(sum);
  1728. }
  1729. for (int mask = 0; mask < (1 << n2); mask++) {
  1730. int sum = 0;
  1731. for (int i = 0; i < n2; i++) if (mask & (1 << i)) sum += arr[n1 + i];
  1732. R.push_back(sum);
  1733. }
  1734. sort(R.begin(), R.end());
  1735. long long ans = 0;
  1736. for (int x : L) {
  1737. ans += upper_bound(R.begin(), R.end(), target - x) - R.begin();
  1738. }
  1739. return ans;
  1740. }
  1741.  
  1742. // --------------------------------------------
  1743. // 52) DP + "Zeta Transform" (SOS DP)
  1744. // --------------------------------------------
  1745. /*
  1746.  * Zeta transform (subset sum) - same as SOS DP.
  1747.  * - zetaTransform: in-place transform.
  1748.  */
  1749.  
  1750. vector<int> zetaTransform(vector<int> f) {
  1751. int n = f.size();
  1752. int bits = 0; while ((1 << bits) < n) bits++;
  1753. for (int i = 0; i < bits; i++) {
  1754. for (int mask = 0; mask < n; mask++) {
  1755. if (mask & (1 << i))
  1756. f[mask] += f[mask ^ (1 << i)];
  1757. }
  1758. }
  1759. return f;
  1760. }
  1761.  
  1762. // --------------------------------------------
  1763. // 53) DP + "LCS Optimized Space"
  1764. // --------------------------------------------
  1765. /*
  1766.  * LCS with O(min(n,m)) space.
  1767.  * - LCS_Optimized: swaps to make second string shorter.
  1768.  */
  1769.  
  1770. int LCS_Optimized(const string& a, const string& b) {
  1771. if (a.size() < b.size()) return LCS_Optimized(b, a);
  1772. int n = a.size(), m = b.size();
  1773. vector<int> dp(m + 1, 0), ndp(m + 1, 0);
  1774. for (int i = 1; i <= n; i++) {
  1775. ndp[0] = 0;
  1776. for (int j = 1; j <= m; j++) {
  1777. if (a[i-1] == b[j-1]) ndp[j] = dp[j-1] + 1;
  1778. else ndp[j] = max(dp[j], ndp[j-1]);
  1779. }
  1780. swap(dp, ndp);
  1781. }
  1782. return dp[m];
  1783. }
  1784.  
  1785. // --------------------------------------------
  1786. // 54) Utility Functions
  1787. // --------------------------------------------
  1788. /*
  1789.  * Common utility functions for DP:
  1790.  * - buildPrefix: 1D prefix sum.
  1791.  * - rangeSum: sum in [l,r].
  1792.  * - buildPrefix2D: 2D prefix sum.
  1793.  * - rectSum: rectangle sum.
  1794.  * - printDP: print 2D DP table (debugging).
  1795.  * - resetMemo: reset memo array to -1.
  1796.  */
  1797.  
  1798. vector<long long> buildPrefix(const vector<long long>& arr) {
  1799. int n = arr.size();
  1800. vector<long long> pref(n + 1, 0);
  1801. for (int i = 0; i < n; i++) pref[i + 1] = pref[i] + arr[i];
  1802. return pref;
  1803. }
  1804.  
  1805. long long rangeSum(const vector<long long>& pref, int l, int r) {
  1806. return pref[r + 1] - pref[l];
  1807. }
  1808.  
  1809. vector<vector<long long>> buildPrefix2D(const vector<vector<long long>>& grid) {
  1810. int n = grid.size(), m = grid[0].size();
  1811. vector<vector<long long>> pref(n + 1, vector<long long>(m + 1, 0));
  1812. for (int i = 0; i < n; i++) {
  1813. for (int j = 0; j < m; j++) {
  1814. pref[i + 1][j + 1] = grid[i][j] + pref[i][j + 1] + pref[i + 1][j] - pref[i][j];
  1815. }
  1816. }
  1817. return pref;
  1818. }
  1819.  
  1820. long long rectSum(const vector<vector<long long>>& pref, int x1, int y1, int x2, int y2) {
  1821. return pref[x2 + 1][y2 + 1] - pref[x1][y2 + 1] - pref[x2 + 1][y1] + pref[x1][y1];
  1822. }
  1823.  
  1824. template<typename T>
  1825. void printDP(const vector<vector<T>>& dp) {
  1826. for (auto &row : dp) {
  1827. for (auto &val : row) cout << val << ' ';
  1828. cout << '\n';
  1829. }
  1830. }
  1831.  
  1832. void resetMemo(long long memo[], int size) {
  1833. for (int i = 0; i < size; i++) memo[i] = -1;
  1834. }
  1835.  
  1836. // --------------------------------------------
  1837. // 55) Additional: DP for "Can Partition K Subsets"
  1838. // --------------------------------------------
  1839. /*
  1840.  * Check if array can be partitioned into k subsets with equal sum.
  1841.  * - canPartitionKSubsets: bitmask DP, O(k * 2^n) or O(n * 2^n).
  1842.  */
  1843.  
  1844. bool canPartitionKSubsets(const vector<int>& nums, int k) {
  1845. int sum = accumulate(nums.begin(), nums.end(), 0);
  1846. if (sum % k != 0) return false;
  1847. int target = sum / k;
  1848. int n = nums.size();
  1849. vector<int> dp(1 << n, -1);
  1850. dp[0] = 0;
  1851. for (int mask = 0; mask < (1 << n); mask++) {
  1852. if (dp[mask] == -1) continue;
  1853. for (int i = 0; i < n; i++) {
  1854. if (!(mask & (1 << i)) && dp[mask] + nums[i] <= target) {
  1855. int newMask = mask | (1 << i);
  1856. int newSum = (dp[mask] + nums[i]) % target;
  1857. if (dp[newMask] == -1) dp[newMask] = newSum;
  1858. }
  1859. }
  1860. }
  1861. return dp[(1 << n) - 1] == 0;
  1862. }
  1863.  
  1864. // --------------------------------------------
  1865. // 56) DP + "Max Sum of Non-Adjacent Elements" (House Robber)
  1866. // --------------------------------------------
  1867. /*
  1868.  * House Robber problems.
  1869.  * - houseRobber: linear array.
  1870.  * - houseRobberCircular: circular array (first and last adjacent).
  1871.  */
  1872.  
  1873. long long houseRobber(const vector<int>& nums) {
  1874. int n = nums.size();
  1875. if (n == 0) return 0;
  1876. if (n == 1) return nums[0];
  1877. vector<long long> dp(n, 0);
  1878. dp[0] = nums[0];
  1879. dp[1] = max(nums[0], nums[1]);
  1880. for (int i = 2; i < n; i++) {
  1881. dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
  1882. }
  1883. return dp[n - 1];
  1884. }
  1885.  
  1886. long long houseRobberCircular(const vector<int>& nums) {
  1887. int n = nums.size();
  1888. if (n == 0) return 0;
  1889. if (n == 1) return nums[0];
  1890. vector<int> a(nums.begin(), nums.end() - 1);
  1891. vector<int> b(nums.begin() + 1, nums.end());
  1892. return max(houseRobber(a), houseRobber(b));
  1893. }
  1894.  
  1895. // --------------------------------------------
  1896. // 57) DP + "Distinct Subsequences" (count of t as subsequence of s)
  1897. // --------------------------------------------
  1898. /*
  1899.  * Count distinct subsequences of s that equal t.
  1900.  * - numDistinct: O(n*m) time and space.
  1901.  */
  1902.  
  1903. int numDistinct(const string& s, const string& t) {
  1904. int n = s.size(), m = t.size();
  1905. vector<vector<long long>> dp(n + 1, vector<long long>(m + 1, 0));
  1906. for (int i = 0; i <= n; i++) dp[i][0] = 1;
  1907. for (int i = 1; i <= n; i++) {
  1908. for (int j = 1; j <= m; j++) {
  1909. dp[i][j] = dp[i - 1][j];
  1910. if (s[i - 1] == t[j - 1]) dp[i][j] += dp[i - 1][j - 1];
  1911. }
  1912. }
  1913. return dp[n][m];
  1914. }
  1915.  
  1916. // =====================================================================
  1917. // EXAMPLE MAIN
  1918. // =====================================================================
  1919.  
  1920. int main() {
  1921. ios::sync_with_stdio(false);
  1922. cin.tie(nullptr);
  1923.  
  1924. // Example usage of some functions:
  1925. vector<int> arr = {10, 9, 2, 5, 3, 7, 101, 18};
  1926. cout << "LIS length = " << LIS(arr) << '\n';
  1927.  
  1928. vector<int> weight = {2, 3, 4, 5};
  1929. vector<int> value = {3, 4, 5, 6};
  1930. int W = 5;
  1931. cout << "Knapsack max value = " << knapsack01(weight, value, W) << '\n';
  1932.  
  1933. initComb(); // if using nCr
  1934. cout << "Fib(10) = " << fibOptimized(10) << '\n';
  1935.  
  1936. string s = "leetcode";
  1937. vector<string> dict = {"leet", "code"};
  1938. cout << "Word Break: " << wordBreak(s, dict) << '\n';
  1939.  
  1940. vector<int> houses = {2, 7, 9, 3, 1};
  1941. cout << "House Robber: " << houseRobber(houses) << '\n';
  1942.  
  1943. vector<int> dims = {40, 20, 30, 10, 30};
  1944. cout << "Matrix Chain Min Cost: " << matrixChainOrder(dims) << '\n';
  1945.  
  1946. string pal = "aab";
  1947. cout << "Min cuts for palindrome: " << minCutPalindrome(pal) << '\n';
  1948.  
  1949. cout << "10th ugly number: " << nthUglyNumber(10) << '\n';
  1950.  
  1951. return 0;
  1952. }
Success #stdin #stdout 0.01s 21132KB
stdin
Standard input is empty
stdout
LIS length = 4
Knapsack max value = 7
Fib(10) = 55
Word Break: 1
House Robber: 12
Matrix Chain Min Cost: 26000
Min cuts for palindrome: 1
10th ugly number: 12