diff --git a/.vscode/settings.json b/.vscode/settings.json index 6f41438931de..4f6b205da12a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -104,7 +104,16 @@ "__node_handle": "cpp", "__verbose_abort": "cpp", "execution": "cpp", - "print": "cpp" + "print": "cpp", + "filesystem": "cpp", + "format": "cpp", + "ccomplex": "cpp", + "cstdbool": "cpp", + "ctgmath": "cpp", + "__assert": "cpp", + "ranges": "cpp", + "version": "cpp", + "bit": "cpp" }, "editor.mouseWheelZoom": true, "workbench.tree.enableStickyScroll": true, diff --git a/Codes/1039-minimum-score-triangulation-of-polygon.cpp b/Codes/1039-minimum-score-triangulation-of-polygon.cpp new file mode 100644 index 000000000000..518b7a61c721 --- /dev/null +++ b/Codes/1039-minimum-score-triangulation-of-polygon.cpp @@ -0,0 +1,35 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-29 18:44:48 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-10-01 19:58:47 + */ +#if defined(_WIN32) || defined(__APPLE__) +#include "_[1,2]toVector.h" +#endif + +#if false // this doesn't work +// 相邻两点乘积的和 + (n-1)条边乘积的2倍 +// 但是不能相交 +// 诶,好像直接最小的那个去连其他所有剩下的就好了 +class Solution { +public: + int minScoreTriangulation(vector& values) { + int ans = values[0] * values.back(); + int m = values[0], loc = 0; + for (int i = 1; i < values.size(); i++) { + ans += values[i - 1] * values[i]; + if (values[i] < m) { + m = values[i]; + loc = i; + } + } + for (int i = 0; i < values.size(); i++) { + if (abs(i - loc) > 1) { + ans += m * values[i] * 2; + } + } + return ans; + } +}; +#endif \ No newline at end of file diff --git a/Codes/1039-minimum-score-triangulation-of-polygon_Ok.cpp b/Codes/1039-minimum-score-triangulation-of-polygon_Ok.cpp new file mode 100644 index 000000000000..1aba4f7eb88e --- /dev/null +++ b/Codes/1039-minimum-score-triangulation-of-polygon_Ok.cpp @@ -0,0 +1,77 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-29 18:44:48 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-10-01 20:38:27 + */ +#if defined(_WIN32) || defined(__APPLE__) +#include "_[1,2]toVector.h" +#endif + +class Solution { +private: + unordered_map cache; + vector values; + int n; + + int dfs(int i, int j) { + if (j - i < 2) { + return 0; + } + int key = i * n + j; + if (cache.count(key)) { + return cache[key]; + } + if (j - i == 2) { + return cache[key] = values[i] * values[i + 1] * values[i + 2]; + } + int ans = 1000000000; + /* + 0 1 2 3 -> 0 1 2 + 0 2 3 + + 0 1 + + 3 2 + + + 0 1 2 3 4 + + + 3 + + 4 2 + + 0 1 + + + (i,j,k) + dfs(i,k)+dfs(k,j) + */ + for (int k = i + 1; k < j; k++) { + ans = min(ans, dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j]); + } + return cache[key] = ans; + } +public: + int minScoreTriangulation(vector& values) { + this->values = move(values); + n = this->values.size(); + return dfs(0, n - 1); + } +}; + +#if defined(_WIN32) || defined(__APPLE__) +/* +[3,7,4,5] + +144 +*/ +int main() { + string s; + while (cin >> s) { + vector v = stringToVector(s); + Solution sol; + cout << sol.minScoreTriangulation(v) << endl; + } + return 0; +} +#endif \ No newline at end of file diff --git a/Codes/lib.rs b/Codes/lib.rs index 0d9f68536624..9ca075feb040 100644 --- a/Codes/lib.rs +++ b/Codes/lib.rs @@ -2,7 +2,7 @@ * @Author: LetMeFly * @Date: 2025-08-07 14:11:36 * @LastEditors: LetMeFly.xyz - * @LastEditTime: 2025-09-07 23:24:39 + * @LastEditTime: 2025-10-01 20:40:27 */ pub struct Solution; include!("0976-largest-perimeter-triangle.rs"); // 这个fileName是会被脚本替换掉的 diff --git a/Codes/pinduoduo-01.py b/Codes/pinduoduo-01.py new file mode 100644 index 000000000000..9381ae481dbf --- /dev/null +++ b/Codes/pinduoduo-01.py @@ -0,0 +1,25 @@ +''' +Author: LetMeFly +Date: 2025-09-28 19:01:34 +LastEditors: LetMeFly.xyz +LastEditTime: 2025-09-28 19:06:41 +''' +a = input() +if len(a) != 9: + print('Invalid') + exit(0) +for i in range(2): + if not 'A' <= a[i] <= 'Z': + print('Invalid') + exit(0) +for i in range(2, 8): + if not a[i].isdigit(): + print('Invalid') + exit(0) +should = 0 +for i in range(8): + should += ord(a[i]) +should %= 26 +should = chr(should + ord('A')) +a = a[:-1] + should +print(a) diff --git a/Codes/pinduoduo-02.cpp b/Codes/pinduoduo-02.cpp new file mode 100644 index 000000000000..cae88f264387 --- /dev/null +++ b/Codes/pinduoduo-02.cpp @@ -0,0 +1,118 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 19:10:08 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 19:31:14 + */ +/* + + 1 + 2 3 +0 1 + + 2 + 3 1 +0 2 + + + +root 1->2 +times: 1 +2->3: 1 +need: 1 +1 -> 2: 1 +need: 1 +3->1: +need: 3 +times: 2 +sum: 1+2=3 +*/ + + +/* + + 1 + 2 3 +1 2 3 1 + + + 3 + 1 2 +3 1 2 1 + +1->3: 2 +times: 2 +2->1: 4 +times: 2 +3->2: 4 +times: 2 +1->3: (5->3) 3 +times: 3 +2->1: (1->1) 0 +3->2: (2->2) 0 +1->1: (5->1) 1 +times 1 +sum: 2 + 2 + 2 + 3 + 1 = 10 +*/ +#include +using namespace std; +typedef long long ll; + +struct Node { + int original, to; + Node *left, *right; + int already; // 由于father导致的已变更次数 +}; + +// 变化范围是1,2,3,4,5 +inline int change(int original, int times) { + return (original + times - 1 + 5) % 5 + 1; +} + +inline int calc(int from, int to) { + return (to - from + 5) % 5; +} + +/* +5 +1 2 3 0 1 +2 3 1 0 2 + +*/ + +int main() { + int n; + cin >> n; + queue q; + Node* head = new Node(); + q.push(head); + for (int i = 0; i < n; i++) { + Node* thisNode = q.front(); + q.pop(); + cin >> thisNode->original; + thisNode->left = new Node(); + thisNode->right = new Node(); + q.push(thisNode->left); + q.push(thisNode->right); + } + q = queue(); + q.push(head); + ll ans = 0; + for (int i = 0; i < n; i++) { + Node* thisNode = q.front(); + q.pop(); + cin >> thisNode->to; + q.push(thisNode->left); + q.push(thisNode->right); + if (thisNode->original == 0) { + continue; + } + int from = change(thisNode->original, thisNode->already); + int need = calc(from, thisNode->to); + ans += need; + thisNode->left->already = (thisNode->already + need) % 5; + thisNode->right->already = (thisNode->already + need) % 5; + } + cout << ans << endl; + return 0; +} \ No newline at end of file diff --git a/Codes/pinduoduo-3-try01-19.61Percent.cpp b/Codes/pinduoduo-3-try01-19.61Percent.cpp new file mode 100644 index 000000000000..00dc5f4a1a2c --- /dev/null +++ b/Codes/pinduoduo-3-try01-19.61Percent.cpp @@ -0,0 +1,116 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 19:37:00 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 19:49:00 + */ +/* +共有n门课程,每个课程有两个属性: +1. power:学习后可以提升的能力值 +2. cost:学习这门课程需要的代价 +学院共有m层楼,每层有不同的环境加成系数bonus[j](1<=bouns[j]<=3) +多多总共有M点初始金币,学习规则如下: +1. 必须按顺序学习课程 +2. 一门课只能在一层完成,不能跨层 +3. 在第j层学习第i门课程时,需要消耗cost[i] * bonus[j]的金币 +4. 在第j层学习第i门课程后,会提升power[i] * bonus[j]的能力值 +5. 多多可以在楼层间切换,第一次选择楼层没有代价,每次切换时:若从低层切换到高层,消耗楼层高度差到代价(如从第1层切换到第3层,消耗2的代价);若从高层切换到低层,则不消化代价。 +请求出总消耗不超过M的前提下最大能力值提升 + +输入: +第一行三个整数n m M (1 <= n <= 100, 1 <= m <= 5, 1 <= M <= 1000) +第二行n个整数power[i] (1 <= power[i] <= 100) +第三行n个整数cost[i] (1 <= cost[i] <= 100) +第四行m个整数bonus[j] (1 <= bonus[j] <= 3) + +输出:一个整数代表可以提升的最大能力值 +*/ +/* +这个问题可以用三维动态规划来解决: + +定义状态:dp[i][j][k]表示学完前i门课程,当前在第j层,总消耗为k的情况下能获得的最大能力值。 + +初始化:初始状态下,没有学习任何课程,所以在任意楼层、消耗0金币时,能力值为0。 + +状态转移:对于每一个状态dp[i][j][k],我们有两种选择: + +继续在当前楼层j学习第i+1门课程 +切换到其他楼层l后学习第i+1门课程(如果从低层切换到高层需要支付楼层高度差的代价) +最终结果:遍历所有学完n门课程的状态,找出消耗不超过M金币的最大能力值。 + +时间复杂度:O(n * m * M * m),其中n是课程数,m是楼层数,M是初始金币数。由于题目限制n<=100, m<=5, M<=1000,这个算法的复杂度是可接受的。 + +空间复杂度:O(n * m * M),主要是动态规划数组的空间消耗。 +*/ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 19:37:00 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 19:49:00 + */ +#include +#include +#include +using namespace std; + +int main() { + int n, m, M; + cin >> n >> m >> M; + vector power(n); + for (int i = 0; i < n; i++) { + cin >> power[i]; + } + vector cost(n); + for (int i = 0; i < n; i++) { + cin >> cost[i]; + } + vector bonus(m); + for (int i = 0; i < m; i++) { + cin >> bonus[i]; + } + // dp[i][j][k] 表示学完前i门课程,当前在第j层,总消耗为k的情况下能获得的最大能力值 + vector>> dp(n + 1, vector>(m, vector(M + 1, -1))); + for (int j = 0; j < m; j++) { + dp[0][j][0] = 0; + } + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + for (int k = 0; k <= M; k++) { + if (dp[i][j][k] == -1) { + continue; + } + // 选择继续在j层学习第i+1门课 + int newCost = k + cost[i] * bonus[j]; + int newPower = dp[i][j][k] + power[i] * bonus[j]; + if (newCost <= M && newPower > dp[i + 1][j][newCost]) { + dp[i + 1][j][newCost] = newPower; + } + // 选择切换到其他楼层l,然后学习第i+1门课 + for (int l = 0; l < m; l++) { + if (l == j) { + continue; + } + int switchCost = 0; + if (l > j) { + switchCost = l - j; + } + newCost = k + switchCost + cost[i] * bonus[l]; + newPower = dp[i][j][k] + power[i] * bonus[l]; + if (newCost <= M && newPower > dp[i + 1][l][newCost]) { + dp[i + 1][l][newCost] = newPower; + } + } + } + } + } + + int maxPower = 0; + for (int j = 0; j < m; j++) { + for (int k = 0; k <= M; k++) { + maxPower = max(maxPower, dp[n][j][k]); + } + } + cout << maxPower << endl; + + return 0; +} \ No newline at end of file diff --git a/Codes/pinduoduo-3-try02-still19.61Percent.cpp b/Codes/pinduoduo-3-try02-still19.61Percent.cpp new file mode 100644 index 000000000000..bb063934cafe --- /dev/null +++ b/Codes/pinduoduo-3-try02-still19.61Percent.cpp @@ -0,0 +1,112 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 19:37:00 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 19:54:20 + */ +/* +共有n门课程,每个课程有两个属性: +1. power:学习后可以提升的能力值 +2. cost:学习这门课程需要的代价 +学院共有m层楼,每层有不同的环境加成系数bonus[j](1<=bouns[j]<=3) +多多总共有M点初始金币,学习规则如下: +1. 必须按顺序学习课程 +2. 一门课只能在一层完成,不能跨层 +3. 在第j层学习第i门课程时,需要消耗cost[i] * bonus[j]的金币 +4. 在第j层学习第i门课程后,会提升power[i] * bonus[j]的能力值 +5. 多多可以在楼层间切换,第一次选择楼层没有代价,每次切换时:若从低层切换到高层,消耗楼层高度差到代价(如从第1层切换到第3层,消耗2的代价);若从高层切换到低层,则不消化代价。 +请求出总消耗不超过M的前提下最大能力值提升 + +输入: +第一行三个整数n m M (1 <= n <= 100, 1 <= m <= 5, 1 <= M <= 1000) +第二行n个整数power[i] (1 <= power[i] <= 100) +第三行n个整数cost[i] (1 <= cost[i] <= 100) +第四行m个整数bonus[j] (1 <= bonus[j] <= 3) + +输出:一个整数代表可以提升的最大能力值 +*/ +/* +这个问题可以用三维动态规划来解决: + +定义状态:dp[i][j][k]表示学完前i门课程,当前在第j层,总消耗为k的情况下能获得的最大能力值。 + +初始化:初始状态下,没有学习任何课程,所以在任意楼层、消耗0金币时,能力值为0。 + +状态转移:对于每一个状态dp[i][j][k],我们有两种选择: + +继续在当前楼层j学习第i+1门课程 +切换到其他楼层l后学习第i+1门课程(如果从低层切换到高层需要支付楼层高度差的代价) +最终结果:遍历所有学完n门课程的状态,找出消耗不超过M金币的最大能力值。 + +时间复杂度:O(n * m * M * m),其中n是课程数,m是楼层数,M是初始金币数。由于题目限制n<=100, m<=5, M<=1000,这个算法的复杂度是可接受的。 + +空间复杂度:O(n * m * M),主要是动态规划数组的空间消耗。 +*/ +#include +#include +#include +using namespace std; + +int main() { + int n, m, M; + cin >> n >> m >> M; + vector power(n); + for (int i = 0; i < n; i++) { + cin >> power[i]; + } + vector cost(n); + for (int i = 0; i < n; i++) { + cin >> cost[i]; + } + vector bonus(m); + for (int i = 0; i < m; i++) { + cin >> bonus[i]; + } + // dp[i][j][k] 表示学完前i门课程,当前在第j层,总消耗为k的情况下能获得的最大能力值 + vector>> dp(n + 1, vector>(m, vector(M + 1, -1))); + for (int j = 0; j < m; j++) { + dp[0][j][0] = 0; + } + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + for (int k = 0; k <= M; k++) { + if (dp[i][j][k] == -1) { + continue; + } + // 选择继续在j层学习第i+1门课 + int newCost = k + cost[i] * bonus[j]; + int newPower = dp[i][j][k] + power[i] * bonus[j]; + if (newCost <= M && newPower > dp[i + 1][j][newCost]) { + dp[i + 1][j][newCost] = newPower; + } + // 选择切换到其他楼层l,然后学习第i+1门课 + for (int l = 0; l < m; l++) { + if (l == j) { + continue; + } + int switchCost = 0; + if (l > j) { + switchCost = l - j; + } + newCost = k + switchCost + cost[i] * bonus[l]; + newPower = dp[i][j][k] + power[i] * bonus[l]; + if (newCost <= M && newPower > dp[i + 1][l][newCost]) { + dp[i + 1][l][newCost] = newPower; + } + } + } + } + } + + int maxPower = 0; + for (int j = 0; j < m; j++) { + for (int k = 0; k <= M; k++) { + if (dp[n][j][k] != -1) { + maxPower = max(maxPower, dp[n][j][k]); + } + } + } + cout << maxPower << endl; + + return 0; +} \ No newline at end of file diff --git a/Codes/pinduoduo-3-try03-rewrite-still19.61.cpp b/Codes/pinduoduo-3-try03-rewrite-still19.61.cpp new file mode 100644 index 000000000000..d71edda45477 --- /dev/null +++ b/Codes/pinduoduo-3-try03-rewrite-still19.61.cpp @@ -0,0 +1,77 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 19:37:00 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 19:59:46 + */ +/* +共有n门课程,每个课程有两个属性: +1. power:学习后可以提升的能力值 +2. cost:学习这门课程需要的代价 +学院共有m层楼,每层有不同的环境加成系数bonus[j](1<=bouns[j]<=3) +多多总共有M点初始金币,学习规则如下: +1. 必须按顺序学习课程 +2. 一门课只能在一层完成,不能跨层 +3. 在第j层学习第i门课程时,需要消耗cost[i] * bonus[j]的金币 +4. 在第j层学习第i门课程后,会提升power[i] * bonus[j]的能力值 +5. 多多可以在楼层间切换,第一次选择楼层没有代价,每次切换时:若从低层切换到高层,消耗楼层高度差到代价(如从第1层切换到第3层,消耗2的代价);若从高层切换到低层,则不消化代价。 +请求出总消耗不超过M的前提下最大能力值提升 + +输入: +第一行三个整数n m M (1 <= n <= 100, 1 <= m <= 5, 1 <= M <= 1000) +第二行n个整数power[i] (1 <= power[i] <= 100) +第三行n个整数cost[i] (1 <= cost[i] <= 100) +第四行m个整数bonus[j] (1 <= bonus[j] <= 3) + +输出:一个整数代表可以提升的最大能力值 +*/ +#include +using namespace std; + +int main() { + int n, m, M; + cin >> n >> m >> M; + + vector power(n), cost(n), bonus(m); + for (auto& p : power) cin >> p; + for (auto& c : cost) cin >> c; + for (auto& b : bonus) cin >> b; + + // dp[i][j][c] = 前i门课,当前在j层,总消耗c的最大能力 + vector>> dp(n+1, vector>(m, vector(M+1, -1))); + + // 初始化:处理0门课时所有楼层消耗为0 + for (int j = 0; j < m; j++) { + dp[0][j][0] = 0; + } + + for (int i = 1; i <= n; i++) { + for (int j = 0; j < m; j++) { + int cur_cost = cost[i-1] * bonus[j]; + int cur_power = power[i-1] * bonus[j]; + + for (int k = 0; k < m; k++) { // 前一次所在的楼层 + for (int c = 0; c <= M; c++) { + if (dp[i-1][k][c] == -1) continue; + + // 计算楼层切换代价 + int switch_cost = (i == 1) ? 0 : max(j - k, 0); + int total_cost = c + cur_cost + switch_cost; + + if (total_cost > M) continue; + + dp[i][j][total_cost] = max(dp[i][j][total_cost], + dp[i-1][k][c] + cur_power); + } + } + } + } + + int ans = 0; + for (int j = 0; j < m; j++) + for (int c = 0; c <= M; c++) + ans = max(ans, dp[n][j][c]); + + cout << ans << endl; + return 0; +} \ No newline at end of file diff --git a/Codes/pinduoduo-3-try04-AC.cpp b/Codes/pinduoduo-3-try04-AC.cpp new file mode 100644 index 000000000000..dfa5ccebd52c --- /dev/null +++ b/Codes/pinduoduo-3-try04-AC.cpp @@ -0,0 +1,83 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 19:37:00 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:07:49 + */ +/* +共有n门课程,每个课程有两个属性: +1. power:学习后可以提升的能力值 +2. cost:学习这门课程需要的代价 +学院共有m层楼,每层有不同的环境加成系数bonus[j](1<=bouns[j]<=3) +多多总共有M点初始金币,学习规则如下: +1. 必须按顺序学习课程 +2. 一门课只能在一层完成,不能跨层 +3. 在第j层学习第i门课程时,需要消耗cost[i] * bonus[j]的金币 +4. 在第j层学习第i门课程后,会提升power[i] * bonus[j]的能力值 +5. 多多可以在楼层间切换,第一次选择楼层没有代价,每次切换时:若从低层切换到高层,消耗楼层高度差到代价(如从第1层切换到第3层,消耗2的代价);若从高层切换到低层,则不消化代价。 +请求出总消耗不超过M的前提下最大能力值提升 + +输入: +第一行三个整数n m M (1 <= n <= 100, 1 <= m <= 5, 1 <= M <= 1000) +第二行n个整数power[i] (1 <= power[i] <= 100) +第三行n个整数cost[i] (1 <= cost[i] <= 100) +第四行m个整数bonus[j] (1 <= bonus[j] <= 3) + +输出:一个整数代表可以提升的最大能力值 +*/ +/* +这个解决方案使用了三维动态规划: + +dp[i][j][k] 表示学习了前i门课程,当前在第j层,总花费为k时能够获得的最大能力值 +状态转移时,对于每个可能的状态,考虑下一门课程可以在任意楼层学习 +计算课程花费时需要考虑楼层加成系数 +计算楼层切换代价时,只有从低层到高层才需要支付代价 +算法的时间复杂度是 O(n × m² × M),在给定的约束条件下(n ≤ 100, m ≤ 5, M ≤ 1000)是可行的 +*/ +#include +using namespace std; + +int main() { + int n, m, M; + cin >> n >> m >> M; + vector power(n), cost(n), bonus(m); + for (int i = 0; i < n; i++) cin >> power[i]; + for (int i = 0; i < n; i++) cin >> cost[i]; + for (int i = 0; i < m; i++) cin >> bonus[i]; + + // dp[i][j][k]: 前i门课程,当前在第j层,总花费为k时的最大能力值 + vector>> dp(n + 1, vector>(m, vector(M + 1, -1))); + for (int j = 0; j < m; j++) { + dp[0][j][0] = 0; + } + + int ans = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + for (int k = 0; k <= M; k++) { + if (dp[i][j][k] == -1) { + continue; + } + for (int next_j = 0; next_j < m; next_j++) { + int course_cost = cost[i] * bonus[next_j]; + int course_power = power[i] * bonus[next_j]; + int switch_cost = 0; + if (next_j > j) { // 从低层切换到高层 + switch_cost = next_j - j; + } + int total_cost = k + course_cost + switch_cost; + if (total_cost <= M) { + dp[i + 1][next_j][total_cost] = max( + dp[i + 1][next_j][total_cost], + dp[i][j][k] + course_power + ); + ans = max(ans, dp[i + 1][next_j][total_cost]); + } + } + } + } + } + + cout << ans << endl; + return 0; +} \ No newline at end of file diff --git a/Codes/pinduoduo04-try01-wa.cpp b/Codes/pinduoduo04-try01-wa.cpp new file mode 100644 index 000000000000..a91cf6cf9650 --- /dev/null +++ b/Codes/pinduoduo04-try01-wa.cpp @@ -0,0 +1,124 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:13:54 + */ +#include +using namespace std; + +struct Fish { + int index; + long long health; + int left, right; +}; + +int main() { + ios::sync_with_stdio(false); + cin.tie(nullptr); + int n; + cin >> n; + vector a(n); + for (int i = 0; i < n; i++) { + cin >> a[i]; + } + + vector fishes(n); + vector result(n, -1); + for (int i = 0; i < n; i++) { + fishes[i] = {i, a[i], i - 1, i + 1}; + } + + // 血量小优先 + auto cmp = [](const pair& a, const pair& b) { + return a.second > b.second; + }; + priority_queue, vector>, decltype(cmp)> pq(cmp); + + for (int i = 0; i < n; i++) { + pq.push({i, a[i]}); + } + + vector alive(n, true); + int step = 0; + while (!pq.empty()) { + auto [idx, health] = pq.top(); + pq.pop(); + if (!alive[idx] || fishes[idx].health != health) { + continue; + } + int left = fishes[idx].left; + int right = fishes[idx].right; + + // 能否被吃 + bool canBeEaten = false; + if (left >= 0 && alive[left] && fishes[left].health > health) { + canBeEaten = true; + if (result[idx] == -1) { + result[idx] = step + 1; + } + } + if (right < n && alive[right] && fishes[right].health > health) { + canBeEaten = true; + if (result[idx] == -1) { + result[idx] = step + 1; + } + } + + // 这条鱼能吃掉邻居 + if ((left >= 0 && alive[left] && health > fishes[left].health) || + (right < n && alive[right] && health > fishes[right].health)) { + // 优先吃血量较小的邻居 + long long leftHealth = (left >= 0 && alive[left]) ? fishes[left].health : 1e18; + long long rightHealth = (right < n && alive[right]) ? fishes[right].health : 1e18; + + if (leftHealth < rightHealth && leftHealth < health) { + // 吃左边 + fishes[idx].health += leftHealth; + alive[left] = false; + fishes[idx].left = fishes[left].left; + if (fishes[idx].left >= 0) { + fishes[fishes[idx].left].right = idx; + } + pq.push({idx, fishes[idx].health}); + } else if (rightHealth < health) { + // 吃右边 + fishes[idx].health += rightHealth; + alive[right] = false; + fishes[idx].right = fishes[right].right; + if (fishes[idx].right < n) { + fishes[fishes[idx].right].left = idx; + } + pq.push({idx, fishes[idx].health}); + } + } + + step++; + } + + for (int i = 0; i < n; i++) { + cout << result[i]; + if (i < n - 1) { + cout << " "; + } + } + cout << endl; + + return 0; +} + +/* +大鱼吃小鱼游戏,共n条鱼编号1到n,血量a[i] +游戏规则:一条鱼的血量严格大于(不包含等于)它相邻的鱼时,可以吃掉相邻的鱼并增加自身血量,增加血量为被吃掉的鱼的血量。没有任何一条鱼血量严格大于它的邻居时,游戏结束。 +请问:对于每一条鱼,计算在所有可能的进食顺序中,它被其他鱼吃掉所需要的最少次数是多少?若它不可能被吃掉,则输出-1 + +第一行一个正整数n(1<=n<=100000) +第二行n个正整数a[i](1<=a[i]<=100000) +保证n条鱼血量之和不会超过10^10 + +如: +4 +3 2 4 2 +输出 +2 1 2 1 +*/ \ No newline at end of file diff --git a/Codes/pinduoduo04-try02-wa.cpp b/Codes/pinduoduo04-try02-wa.cpp new file mode 100644 index 000000000000..64a221830fec --- /dev/null +++ b/Codes/pinduoduo04-try02-wa.cpp @@ -0,0 +1,122 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:16:38 + */ +#include +#include +#include +#include +using namespace std; + +struct Node { + int idx; + long long val; + int left, right; + bool alive; +}; + +int main() { + ios::sync_with_stdio(false); + cin.tie(nullptr); + + int n; + cin >> n; + vector a(n); + for (int i = 0; i < n; i++) { + cin >> a[i]; + } + + vector nodes(n); + vector ans(n, -1); + + // 初始化双向链表 + for (int i = 0; i < n; i++) { + nodes[i] = {i, a[i], i - 1, i + 1, true}; + } + + // 使用小顶堆,按值从小到大处理 + auto cmp = [](pair a, pair b) { + return a.second > b.second; + }; + priority_queue, vector>, decltype(cmp)> pq(cmp); + + for (int i = 0; i < n; i++) { + pq.push({i, a[i]}); + } + + int step = 0; + while (!pq.empty()) { + auto [idx, val] = pq.top(); + pq.pop(); + + if (!nodes[idx].alive || nodes[idx].val != val) continue; + + int left = nodes[idx].left; + int right = nodes[idx].right; + + // 检查当前鱼是否能被吃掉 + bool canBeEaten = false; + if (left >= 0 && nodes[left].alive && nodes[left].val > val) { + canBeEaten = true; + } + if (right < n && nodes[right].alive && nodes[right].val > val) { + canBeEaten = true; + } + + if (canBeEaten) { + if (ans[idx] == -1) { + ans[idx] = step + 1; + } + } + + // 检查当前鱼是否能吃掉邻居 + if (left >= 0 && nodes[left].alive && val > nodes[left].val) { + // 吃掉左边的鱼 + nodes[idx].val += nodes[left].val; + nodes[left].alive = false; + nodes[idx].left = nodes[left].left; + if (nodes[idx].left >= 0) { + nodes[nodes[idx].left].right = idx; + } + pq.push({idx, nodes[idx].val}); + } else if (right < n && nodes[right].alive && val > nodes[right].val) { + // 吃掉右边的鱼 + nodes[idx].val += nodes[right].val; + nodes[right].alive = false; + nodes[idx].right = nodes[right].right; + if (nodes[idx].right < n) { + nodes[nodes[idx].right].left = idx; + } + pq.push({idx, nodes[idx].val}); + } + + step++; + } + + // 输出结果 + for (int i = 0; i < n; i++) { + cout << ans[i]; + if (i < n - 1) cout << " "; + } + cout << endl; + + return 0; +} + +/* +大鱼吃小鱼游戏,共n条鱼编号1到n,血量a[i] +游戏规则:一条鱼的血量严格大于(不包含等于)它相邻的鱼时,可以吃掉相邻的鱼并增加自身血量,增加血量为被吃掉的鱼的血量。没有任何一条鱼血量严格大于它的邻居时,游戏结束。 +请问:对于每一条鱼,计算在所有可能的进食顺序中,它被其他鱼吃掉所需要的最少次数是多少?若它不可能被吃掉,则输出-1 + +第一行一个正整数n(1<=n<=100000) +第二行n个正整数a[i](1<=a[i]<=100000) +保证n条鱼血量之和不会超过10^10 + +如: +4 +3 2 4 2 +输出 +2 1 2 1 +*/ \ No newline at end of file diff --git a/Codes/pinduoduo04-try03-noOutput.cpp b/Codes/pinduoduo04-try03-noOutput.cpp new file mode 100644 index 000000000000..4f7b2267f6bd --- /dev/null +++ b/Codes/pinduoduo04-try03-noOutput.cpp @@ -0,0 +1,134 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:18:26 + */ +#include +#include +#include +#include +using namespace std; + +struct Node { + int idx; + long long val; + int left, right; + bool alive; + int eatenBy; // 被哪条鱼吃掉 +}; + +int main() { + ios::sync_with_stdio(false); + cin.tie(nullptr); + + int n; + cin >> n; + vector a(n); + for (int i = 0; i < n; i++) { + cin >> a[i]; + } + + vector nodes(n); + vector result(n, -1); + vector steps(n, 0); // 记录被吃掉的步数 + + // 初始化双向链表 + for (int i = 0; i < n; i++) { + nodes[i] = {i, a[i], i - 1, i + 1, true, -1}; + } + + // 使用小顶堆,按值从小到大处理 + auto cmp = [](pair a, pair b) { + return a.second > b.second; + }; + priority_queue, vector>, decltype(cmp)> pq(cmp); + + for (int i = 0; i < n; i++) { + pq.push({i, a[i]}); + } + + int currentStep = 0; + + while (!pq.empty()) { + currentStep++; + auto [idx, val] = pq.top(); + pq.pop(); + + if (!nodes[idx].alive || nodes[idx].val != val) continue; + + int left = nodes[idx].left; + int right = nodes[idx].right; + + // 检查当前鱼是否能被吃掉 + if (left >= 0 && nodes[left].alive && nodes[left].val > val) { + // 被左边鱼吃掉 + if (result[idx] == -1) { + result[idx] = currentStep; + nodes[idx].alive = false; + nodes[idx].eatenBy = left; + + // 更新链表 + if (left >= 0) { + nodes[left].right = right; + } + if (right < n) { + nodes[right].left = left; + } + + // 左边的鱼血量增加 + nodes[left].val += val; + pq.push({left, nodes[left].val}); + } + } + else if (right < n && nodes[right].alive && nodes[right].val > val) { + // 被右边鱼吃掉 + if (result[idx] == -1) { + result[idx] = currentStep; + nodes[idx].alive = false; + nodes[idx].eatenBy = right; + + // 更新链表 + if (left >= 0) { + nodes[left].right = right; + } + if (right < n) { + nodes[right].left = left; + } + + // 右边的鱼血量增加 + nodes[right].val += val; + pq.push({right, nodes[right].val}); + } + } + // 如果当前鱼不能立即被吃掉,重新加入队列等待后续处理 + else if (result[idx] == -1) { + pq.push({idx, val}); + } + } + + // 输出结果 + for (int i = 0; i < n; i++) { + cout << result[i]; + if (i < n - 1) cout << " "; + } + cout << endl; + + return 0; +} + +/* +大鱼吃小鱼游戏,共n条鱼编号1到n,血量a[i] +游戏规则:一条鱼的血量严格大于(不包含等于)它相邻的鱼时,可以吃掉相邻的鱼并增加自身血量,增加血量为被吃掉的鱼的血量。没有任何一条鱼血量严格大于它的邻居时,游戏结束。 +请问:对于每一条鱼,计算在所有可能的进食顺序中,它被其他鱼吃掉所需要的最少次数是多少?若它不可能被吃掉,则输出-1 + +第一行一个正整数n(1<=n<=100000) +第二行n个正整数a[i](1<=a[i]<=100000) +保证n条鱼血量之和不会超过10^10 + +如: +4 +3 2 4 2 +输出 +2 1 2 1 +*/ \ No newline at end of file diff --git a/Codes/pinduoduo04-try04-WA.cpp b/Codes/pinduoduo04-try04-WA.cpp new file mode 100644 index 000000000000..5571628cd906 --- /dev/null +++ b/Codes/pinduoduo04-try04-WA.cpp @@ -0,0 +1,127 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:21:31 + */ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:19:16 + */ +#include +#include +#include +#include +using namespace std; + +vector calculateMinEatTimes(int n, vector& a) { + vector result(n, -1); // 初始化为-1,表示不可能被吃掉 + + // 双向单调栈,用于寻找每个位置左右第一个比它大的元素 + stack leftStack, rightStack; + + // 从左到右处理,寻找右边第一个比当前元素大的元素 + vector rightGreater(n, -1); + for (int i = 0; i < n; ++i) { + while (!rightStack.empty() && a[i] > a[rightStack.top()]) { + rightGreater[rightStack.top()] = i; + rightStack.pop(); + } + rightStack.push(i); + } + + // 从右到左处理,寻找左边第一个比当前元素大的元素 + vector leftGreater(n, -1); + for (int i = n - 1; i >= 0; --i) { + while (!leftStack.empty() && a[i] > a[leftStack.top()]) { + leftGreater[leftStack.top()] = i; + leftStack.pop(); + } + leftStack.push(i); + } + + // 使用动态规划计算每条鱼被吃掉的最少次数 + vector dp(n, -1); + + // 对于每条鱼,检查它是否可能被吃掉 + for (int i = 0; i < n; ++i) { + // 如果左右都没有比它大的鱼,那么它不可能被吃掉 + if (leftGreater[i] == -1 && rightGreater[i] == -1) { + continue; + } + + int minTimes = INT_MAX; + // 检查左边的鱼是否能吃掉它 + if (leftGreater[i] != -1) { + int j = leftGreater[i]; + int times = 1; + // 寻找从左边鱼到当前鱼的最短路径 + while (j < i) { + if (rightGreater[j] != -1 && rightGreater[j] <= i) { + j = rightGreater[j]; + times++; + } else { + break; + } + } + minTimes = times; + } + + // 检查右边的鱼是否能吃掉它 + if (rightGreater[i] != -1) { + int j = rightGreater[i]; + int times = 1; + // 寻找从右边鱼到当前鱼的最短路径 + while (j > i) { + if (leftGreater[j] != -1 && leftGreater[j] >= i) { + j = leftGreater[j]; + times++; + } else { + break; + } + } + minTimes = min(minTimes, times); + } + + dp[i] = minTimes; + } + + return dp; +} + +int main() { + int n; + cin >> n; + vector a(n); + for (int i = 0; i < n; ++i) { + cin >> a[i]; + } + + vector result = calculateMinEatTimes(n, a); + for (int i = 0; i < n; ++i) { + cout << result[i]; + if (i < n - 1) { + cout << " "; + } + } + cout << endl; + + return 0; +} +/* +大鱼吃小鱼游戏,共n条鱼编号1到n,血量a[i] +游戏规则:一条鱼的血量严格大于(不包含等于)它相邻的鱼时,可以吃掉相邻的鱼并增加自身血量,增加血量为被吃掉的鱼的血量。没有任何一条鱼血量严格大于它的邻居时,游戏结束。 +请问:对于每一条鱼,计算在所有可能的进食顺序中,它被其他鱼吃掉所需要的最少次数是多少?若它不可能被吃掉,则输出-1 + +第一行一个正整数n(1<=n<=100000) +第二行n个正整数a[i](1<=a[i]<=100000) +保证n条鱼血量之和不会超过10^10 + +如: +4 +3 2 4 2 +输出 +2 1 2 1 +*/ diff --git a/Codes/pinduoduo04-try05-WA.cpp b/Codes/pinduoduo04-try05-WA.cpp new file mode 100644 index 000000000000..332e4da19f5e --- /dev/null +++ b/Codes/pinduoduo04-try05-WA.cpp @@ -0,0 +1,120 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:32:33 + */ +#include +#include +#include +using namespace std; + +int main() { + ios::sync_with_stdio(false); + cin.tie(nullptr); + + int n; + cin >> n; + vector a(n); + for (int i = 0; i < n; i++) { + cin >> a[i]; + } + + vector ans(n, -1); + + // 对于每条鱼,检查左右两边 + for (int i = 0; i < n; i++) { + // 检查左边 + int left_steps = 0; + int current_power = 0; + bool can_eat_from_left = false; + + for (int j = i - 1; j >= 0; j--) { + if (a[j] > a[i]) { + // 直接能吃掉 + left_steps = 1; + can_eat_from_left = true; + break; + } else if (a[j] < a[i]) { + // 可以被吃掉来积累能量 + current_power += a[j]; + left_steps++; + if (current_power > a[i]) { + can_eat_from_left = true; + break; + } + } else { + // 相等,无法吃掉 + break; + } + } + + // 检查右边 + int right_steps = 0; + current_power = 0; + bool can_eat_from_right = false; + + for (int j = i + 1; j < n; j++) { + if (a[j] > a[i]) { + // 直接能吃掉 + right_steps = 1; + can_eat_from_right = true; + break; + } else if (a[j] < a[i]) { + // 可以被吃掉来积累能量 + current_power += a[j]; + right_steps++; + if (current_power > a[i]) { + can_eat_from_right = true; + break; + } + } else { + // 相等,无法吃掉 + break; + } + } + + // 确定最小步数 + if (can_eat_from_left && can_eat_from_right) { + ans[i] = min(left_steps, right_steps); + } else if (can_eat_from_left) { + ans[i] = left_steps; + } else if (can_eat_from_right) { + ans[i] = right_steps; + } + // 否则保持-1 + } + + // 输出结果 + for (int i = 0; i < n; i++) { + cout << ans[i] << (i < n - 1 ? " " : "\n"); + } + + return 0; +} +/* +大鱼吃小鱼游戏,共n条鱼编号1到n,血量a[i] +游戏规则:一条鱼的血量严格大于(不包含等于)它相邻的鱼时,可以吃掉相邻的鱼并增加自身血量,增加血量为被吃掉的鱼的血量。没有任何一条鱼血量严格大于它的邻居时,游戏结束。 +请问:对于每一条鱼,计算在所有可能的进食顺序中,它被其他鱼吃掉所需要的最少次数是多少?若它不可能被吃掉,则输出-1 + +输入: +第一行一个正整数n(1<=n<=100000) +第二行n个正整数a[i](1<=a[i]<=100000) +保证n条鱼血量之和不会超过10^10 + +输出: +n个整数,第i个整数表示编号为i的鱼被其他鱼吃掉所需要的最少次数;若不可能被吃掉,则输出-1。 + +如: +4 +3 2 4 2 +输出 +2 1 2 1 + +如: +5 +2 2 3 1 1 +输出: +2 1 -1 1 2 + +*/ diff --git a/Codes/pinduoduo04-try06-BaoLi-n2-WA-24.32Percent.cpp b/Codes/pinduoduo04-try06-BaoLi-n2-WA-24.32Percent.cpp new file mode 100644 index 000000000000..87118845816b --- /dev/null +++ b/Codes/pinduoduo04-try06-BaoLi-n2-WA-24.32Percent.cpp @@ -0,0 +1,95 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:36:51 + */ +#include +using namespace std; + +int main() { + ios::sync_with_stdio(false); + cin.tie(nullptr); + + int n; + cin >> n; + vector a(n); + for (int i = 0; i < n; i++) { + cin >> a[i]; + } + + vector ans(n, -1); + + for (int i = 0; i < n; i++) { + bool canBeEaten = false; + int minSteps = n; + + long long power = 0; + int steps = 0; + for (int j = i - 1; j >= 0; j--) { + if (a[j] + power > a[i]) { + canBeEaten = true; + minSteps = min(minSteps, steps + 1); + break; + } else if (a[j] < a[i]) { + power += a[j]; + steps++; + } else { + break; + } + } + + power = 0; + steps = 0; + for (int j = i + 1; j < n; j++) { + if (a[j] + power > a[i]) { + canBeEaten = true; + minSteps = min(minSteps, steps + 1); + break; + } else if (a[j] < a[i]) { + power += a[j]; + steps++; + } else { + break; + } + } + + if (canBeEaten) { + ans[i] = minSteps; + } + } + + for (int i = 0; i < n; i++) { + cout << ans[i]; + if (i < n - 1) cout << " "; + } + cout << "\n"; + + return 0; +} +/* +大鱼吃小鱼游戏,共n条鱼编号1到n,血量a[i] +游戏规则:一条鱼的血量严格大于(不包含等于)它相邻的鱼时,可以吃掉相邻的鱼并增加自身血量,增加血量为被吃掉的鱼的血量。没有任何一条鱼血量严格大于它的邻居时,游戏结束。 +请问:对于每一条鱼,计算在所有可能的进食顺序中,它被其他鱼吃掉所需要的最少次数是多少?若它不可能被吃掉,则输出-1 + +输入: +第一行一个正整数n(1<=n<=100000) +第二行n个正整数a[i](1<=a[i]<=100000) +保证n条鱼血量之和不会超过10^10 + +输出: +n个整数,第i个整数表示编号为i的鱼被其他鱼吃掉所需要的最少次数;若不可能被吃掉,则输出-1。 + +如: +4 +3 2 4 2 +输出 +2 1 2 1 + +如: +5 +2 2 3 1 1 +输出: +2 1 -1 1 2 + +*/ diff --git a/Codes/pinduoduo04-try07-WA.cpp b/Codes/pinduoduo04-try07-WA.cpp new file mode 100644 index 000000000000..fba816bda049 --- /dev/null +++ b/Codes/pinduoduo04-try07-WA.cpp @@ -0,0 +1,127 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:39:45 + */ +#include +#include +#include +#include + +using namespace std; + +int main() { + int n; + cin >> n; + + vector a(n); + for (int i = 0; i < n; i++) { + cin >> a[i]; + } + + vector res(n, -1); + stack st; + + // 从左到右处理,计算右边更大的鱼吃掉当前鱼所需的次数 + for (int i = 0; i < n; i++) { + while (!st.empty() && a[st.top()] < a[i]) { + if (res[st.top()] == -1) { + res[st.top()] = 1; + } else { + res[st.top()] = min(res[st.top()], 1); + } + st.pop(); + } + st.push(i); + } + + // 清空栈,从右到左处理,计算左边更大的鱼吃掉当前鱼所需的次数 + while (!st.empty()) st.pop(); + + for (int i = n - 1; i >= 0; i--) { + while (!st.empty() && a[st.top()] < a[i]) { + if (res[st.top()] == -1) { + res[st.top()] = 1; + } else { + res[st.top()] = min(res[st.top()], 1); + } + st.pop(); + } + st.push(i); + } + + // 现在需要处理更复杂的情况,考虑间接被吃的情况 + // 重新使用单调栈来找到每个元素左右第一个更大的元素 + vector left(n, -1), right(n, -1); + + // 找左边第一个更大的元素 + while (!st.empty()) st.pop(); + for (int i = 0; i < n; i++) { + while (!st.empty() && a[st.top()] <= a[i]) { + st.pop(); + } + if (!st.empty()) { + left[i] = st.top(); + } + st.push(i); + } + + // 找右边第一个更大的元素 + while (!st.empty()) st.pop(); + for (int i = n - 1; i >= 0; i--) { + while (!st.empty() && a[st.top()] <= a[i]) { + st.pop(); + } + if (!st.empty()) { + right[i] = st.top(); + } + st.push(i); + } + + // 根据左右更大的元素来计算最终答案 + for (int i = 0; i < n; i++) { + if (left[i] != -1 && right[i] != -1) { + // 左右都有更大的鱼,需要2次操作 + res[i] = 2; + } else if (left[i] != -1 || right[i] != -1) { + // 只有一边有更大的鱼,需要1次操作 + res[i] = 1; + } + // 否则 res[i] 保持为 -1,表示不会被吃掉 + } + + // 输出结果 + for (int i = 0; i < n; i++) { + cout << res[i] << " "; + } + cout << endl; + + return 0; +} +/* +大鱼吃小鱼游戏,共n条鱼编号1到n,血量a[i] +游戏规则:一条鱼的血量严格大于(不包含等于)它相邻的鱼时,可以吃掉相邻的鱼并增加自身血量,增加血量为被吃掉的鱼的血量。没有任何一条鱼血量严格大于它的邻居时,游戏结束。 +请问:对于每一条鱼,计算在所有可能的进食顺序中,它被其他鱼吃掉所需要的最少次数是多少?若它不可能被吃掉,则输出-1 + +输入: +第一行一个正整数n(1<=n<=100000) +第二行n个正整数a[i](1<=a[i]<=100000) +保证n条鱼血量之和不会超过10^10 + +输出: +n个整数,第i个整数表示编号为i的鱼被其他鱼吃掉所需要的最少次数;若不可能被吃掉,则输出-1。 + +如: +4 +3 2 4 2 +输出 +2 1 2 1 + +如: +5 +2 2 3 1 1 +输出: +2 1 -1 1 2 + +*/ diff --git a/Codes/pinduoduo04-try08-From06-JiaTePan-Still24.32.cpp b/Codes/pinduoduo04-try08-From06-JiaTePan-Still24.32.cpp new file mode 100644 index 000000000000..9283aec3f1a4 --- /dev/null +++ b/Codes/pinduoduo04-try08-From06-JiaTePan-Still24.32.cpp @@ -0,0 +1,118 @@ +/* + * @Author: LetMeFly + * @Date: 2025-09-28 20:05:54 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-09-28 20:41:42 + */ +#include +using namespace std; + +int main() { + ios::sync_with_stdio(false); + cin.tie(nullptr); + + int n; + cin >> n; + vector a(n); + for (int i = 0; i < n; i++) { + cin >> a[i]; + } + + vector ans(n, -1); + + for (int i = 0; i < n; i++) { + bool canBeEaten = false; + int minSteps = n; + + long long power = 0; + int steps = 0; + for (int j = i - 1; j >= 0; j--) { + if (a[j] + power > a[i]) { + canBeEaten = true; + minSteps = min(minSteps, steps + 1); + break; + } else if (a[j] < a[i]) { + power += a[j]; + steps++; + } else { + break; + } + } + + power = 0; + steps = 0; + for (int j = i + 1; j < n; j++) { + if (a[j] + power > a[i]) { + canBeEaten = true; + minSteps = min(minSteps, steps + 1); + break; + } else if (a[j] < a[i]) { + power += a[j]; + steps++; + } else { + break; + } + } + + if (canBeEaten) { + ans[i] = minSteps; + } + } + + // 特判:当所有鱼都无法被吃掉时,全部输出-1 + bool allCannotBeEaten = true; + for (int i = 0; i < n; i++) { + if (ans[i] != -1) { + allCannotBeEaten = false; + break; + } + } + + if (allCannotBeEaten) { + // 全部输出-1(已经是默认值,无需修改) + } else { + // 否则按原逻辑输出结果 + for (int i = 0; i < n; i++) { + cout << ans[i]; + if (i < n - 1) cout << " "; + } + cout << "\n"; + } + + // 如果所有鱼都无法被吃掉,输出n个-1 + if (allCannotBeEaten) { + for (int i = 0; i < n; i++) { + cout << "-1"; + if (i < n - 1) cout << " "; + } + cout << "\n"; + } + + return 0; +} +/* +大鱼吃小鱼游戏,共n条鱼编号1到n,血量a[i] +游戏规则:一条鱼的血量严格大于(不包含等于)它相邻的鱼时,可以吃掉相邻的鱼并增加自身血量,增加血量为被吃掉的鱼的血量。没有任何一条鱼血量严格大于它的邻居时,游戏结束。 +请问:对于每一条鱼,计算在所有可能的进食顺序中,它被其他鱼吃掉所需要的最少次数是多少?若它不可能被吃掉,则输出-1 + +输入: +第一行一个正整数n(1<=n<=100000) +第二行n个正整数a[i](1<=a[i]<=100000) +保证n条鱼血量之和不会超过10^10 + +输出: +n个整数,第i个整数表示编号为i的鱼被其他鱼吃掉所需要的最少次数;若不可能被吃掉,则输出-1。 + +如: +4 +3 2 4 2 +输出 +2 1 2 1 + +如: +5 +2 2 3 1 1 +输出: +2 1 -1 1 2 + +*/ diff --git a/README.md b/README.md index 55eb9366fe83..56af0ddbd553 100644 --- a/README.md +++ b/README.md @@ -478,6 +478,7 @@ |1033.移动石子直到连续|中等|题目地址|题解地址|CSDN题解|LeetCode题解| |1037.有效的回旋镖|简单|题目地址|题解地址|CSDN题解|LeetCode题解| |1038.从二叉搜索树到更大和树|中等|题目地址|题解地址|CSDN题解|LeetCode题解| +|1039.多边形三角剖分的最低得分|中等|题目地址|题解地址|CSDN题解|LeetCode题解| |1041.困于环中的机器人|中等|题目地址|题解地址|CSDN题解|LeetCode题解| |1042.不邻接植花|中等|题目地址|题解地址|CSDN题解|LeetCode题解| |1052.爱生气的书店老板|中等|题目地址|题解地址|CSDN题解|LeetCode题解| diff --git "a/Solutions/LeetCode 1039.\345\244\232\350\276\271\345\275\242\344\270\211\350\247\222\345\211\226\345\210\206\347\232\204\346\234\200\344\275\216\345\276\227\345\210\206.md" "b/Solutions/LeetCode 1039.\345\244\232\350\276\271\345\275\242\344\270\211\350\247\222\345\211\226\345\210\206\347\232\204\346\234\200\344\275\216\345\276\227\345\210\206.md" new file mode 100644 index 000000000000..3b185b5ea629 --- /dev/null +++ "b/Solutions/LeetCode 1039.\345\244\232\350\276\271\345\275\242\344\270\211\350\247\222\345\211\226\345\210\206\347\232\204\346\234\200\344\275\216\345\276\227\345\210\206.md" @@ -0,0 +1,165 @@ +--- +title: 1039.多边形三角剖分的最低得分:记忆化搜索(深度优先搜索) +date: 2025-10-01 20:40:37 +tags: [题解, LeetCode, 中等, 数组, DFS, 深度优先搜索, 记忆化搜索] +categories: [题解, LeetCode] +--- + +# 【LetMeFly】1039.多边形三角剖分的最低得分:记忆化搜索(深度优先搜索) + +力扣题目链接:[https://leetcode.cn/problems/minimum-score-triangulation-of-polygon/](https://leetcode.cn/problems/minimum-score-triangulation-of-polygon/) + +

你有一个凸的 n 边形,其每个顶点都有一个整数值。给定一个整数数组 values ,其中 values[i] 是第 i 个顶点的值(即 顺时针顺序 )。

+ +

假设将多边形 剖分 为 n - 2 个三角形。对于每个三角形,该三角形的值是顶点标记的乘积,三角剖分的分数是进行三角剖分后所有 n - 2 个三角形的值之和。

+ +

返回 多边形进行三角剖分后可以得到的最低分

+ +
    +
+ +

示例 1:

+ +

+ +
+输入:values = [1,2,3]
+输出:6
+解释:多边形已经三角化,唯一三角形的分数为 6。
+
+ +

示例 2:

+ +

+ +
+输入:values = [3,7,4,5]
+输出:144
+解释:有两种三角剖分,可能得分分别为:3*7*5 + 4*5*7 = 245,或 3*4*5 + 3*4*7 = 144。最低分数为 144。
+
+ +

示例 3:

+ +

+ +
+输入:values = [1,3,1,4,1,5]
+输出:13
+解释:最低分数三角剖分的得分情况为 1*1*3 + 1*1*4 + 1*1*5 + 1*1*1 = 13。
+
+ +

 

+ +

提示:

+ +
    +
  • n == values.length
  • +
  • 3 <= n <= 50
  • +
  • 1 <= values[i] <= 100
  • +
+ + + +## 解题方法:DFS + +借一张[@灵茶山艾府](https://leetcode.cn/u/endlesscheng/)的[图](https://leetcode.cn/problems/minimum-score-triangulation-of-polygon/solutions/2203005/shi-pin-jiao-ni-yi-bu-bu-si-kao-dong-tai-aty6/): + +![5时示例图](https://cors.letmefly.xyz/https://i-blog.csdnimg.cn/direct/61d6f9b28c9345e0a18fafcd758422a0.png#pic_center) + + + +以边`1-5`为例,这条边最终一定在一个三角形中。在哪个三角形中呢?一共有图中这四种可能。我们分别枚举这4种可能就好了。 + +具体来说,我们可以写一个函数`dfs(i, j)`,代表从`i`到`j`的凸多边形的最低得分,那么将点`k`作为边`15`所在三角形的另一个顶点的话,得到的总得分为`dfs(i, k)+dfs(k, j) + i*j*k`。 + ++ 时间复杂度$O(n^3)$ ++ 空间复杂度$O(n^2)$ + +### AC代码 + +#### C++ + +```cpp +/* + * @Author: LetMeFly + * @Date: 2025-09-29 18:44:48 + * @LastEditors: LetMeFly.xyz + * @LastEditTime: 2025-10-01 20:38:27 + */ +#if defined(_WIN32) || defined(__APPLE__) +#include "_[1,2]toVector.h" +#endif + +class Solution { +private: + unordered_map cache; + vector values; + int n; + + int dfs(int i, int j) { + if (j - i < 2) { + return 0; + } + int key = i * n + j; + if (cache.count(key)) { + return cache[key]; + } + if (j - i == 2) { + return cache[key] = values[i] * values[i + 1] * values[i + 2]; + } + int ans = 1000000000; + /* + 0 1 2 3 -> 0 1 2 + 0 2 3 + + 0 1 + + 3 2 + + + 0 1 2 3 4 + + + 3 + + 4 2 + + 0 1 + + + (i,j,k) + dfs(i,k)+dfs(k,j) + */ + for (int k = i + 1; k < j; k++) { + ans = min(ans, dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j]); + } + return cache[key] = ans; + } +public: + int minScoreTriangulation(vector& values) { + this->values = move(values); + n = this->values.size(); + return dfs(0, n - 1); + } +}; + +#if defined(_WIN32) || defined(__APPLE__) +/* +[3,7,4,5] + +144 +*/ +int main() { + string s; + while (cin >> s) { + vector v = stringToVector(s); + Solution sol; + cout << sol.minScoreTriangulation(v) << endl; + } + return 0; +} +#endif +``` + +> 同步发文于[CSDN](https://letmefly.blog.csdn.net/article/details/152376690)和我的[个人博客](https://blog.letmefly.xyz/),原创不易,转载经作者同意后请附上[原文链接](https://blog.letmefly.xyz/2025/09/29/LeetCode%201039.%E5%A4%9A%E8%BE%B9%E5%BD%A2%E4%B8%89%E8%A7%92%E5%89%96%E5%88%86%E7%9A%84%E6%9C%80%E4%BD%8E%E5%BE%97%E5%88%86/)哦~ +> +> 千篇源码题解[已开源](https://github.com/LetMeFly666/LeetCode) diff --git a/Solutions/Other-English-LearningNotes-SomeWords.md b/Solutions/Other-English-LearningNotes-SomeWords.md index eec8fa866850..547095651d9b 100644 --- a/Solutions/Other-English-LearningNotes-SomeWords.md +++ b/Solutions/Other-English-LearningNotes-SomeWords.md @@ -1478,6 +1478,14 @@ categories: [自用] |pitcher|n. 壶,罐,投球手| |short-weight|v. 缺斤短两| |radish|n. (小)萝卜| +||| +|sieve|n. 筛子,漏斗,滤器,笊篱
v. 筛,滤| +|exempt|v. 豁免
adj. 获豁免的,被免除的
n. 被免除(责任/义务)的人,免税人
例句She is exempt from the exam.
她被免除了考试。
| +|deflate|v. 放气,使泄气,挫败...的锐气| +||| +|yoke|n. 束缚,枷锁,奴役
v. 给(动物)上轭,(强行)使结合| +||| +|liberal|adj. 开朗的,自由的
n. 自由勇敢者| + 这个web要是能设计得可以闭眼(完全不睁眼)键盘控制背单词就好了。 + 也许可以加个AI用最近词编故事功能(返回接口中支持标注所使用单词高亮?) diff --git a/Solutions/Other-Japanese-LearningNotes.md b/Solutions/Other-Japanese-LearningNotes.md index 138fe7939e43..6bdf0a42bf18 100644 --- a/Solutions/Other-Japanese-LearningNotes.md +++ b/Solutions/Other-Japanese-LearningNotes.md @@ -163,6 +163,7 @@ xx型 |買い(かい)|买| |入れ(いれ)|预约(v.)| |予約(よやく)|预约(n.)| +|チェックイン(checkin)|入住| |セール(sale)|促销| |返品(へんぴん)|退货| |捨て(すて)|仍| @@ -220,6 +221,7 @@ xx型 |走り(はしり)|跑步| |空手(からて)|空手道| |さんぽ|散步| +|引っ越し(ひっこし)|搬家| |アクション|动作| |スポーツ|运动(名词)| |運動(うんどう)|运动(动词)| @@ -1480,7 +1482,7 @@ xx型 |どこかに行きませんか。
要不要去某个地方呢?| |ちゃんと日焼け止め日焼け止めを使いましょう。
我们好好地用防晒霜吧。| |ここから離れましょう。
我们从这里离开吧。| -|
| +|チェックインをお願いします。
请办理入住。| |
| TODO: おしゃれなサングラス サングラス