P5414 [YNOI2019] 排序 - 洛谷
思路:
可以想到對于任意一個需要換位置的數字,我們不可能換兩次及以上,那么這題就可以轉化為求一個最大和的最長不遞減子序列,最后的答案就是眾和減去這個最大和
代碼:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endlvoid solve()
{int n;cin >> n;vector<int> a(n),b(n,0);int sum = 0;for (int i = 0; i < n; i++){cin >> a[i];for (int j = 0; j < i; j++){if (a[j] <= a[i]){b[i] = max(b[i], b[j]);}}b[i] += a[i];sum += a[i];}int mx = 0;for (int i = 0; i < n; i++){mx = max(mx, b[i]);}cout << sum - mx << endl;
}
signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}
P2690 [USACO04NOV] Apple Catching G - 洛谷
思路:
這一題讓我們求在最多w次換位中能接到的最多蘋果數,一個顯然的想法就是 定義dp[i]為前i個蘋果中能接到的最大值,但是我們發現我們無法判斷當前蘋果能不能選,所以我們還要一維來判斷能不能選當前蘋果,這里我們就定義 dp[i][j] 為前 i 個蘋果中進行了 j 次換位能獲得最大值,這樣我們就能判斷能否選擇了,顯然當換位次數是奇數時,我們就能選 2,否則就是選 1
代碼:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endlvoid solve()
{int t, w;cin >> t >> w;vector<int> a(t+1);for (int i = 1; i <= t; i++){cin >> a[i];a[i]--;}vector<vector<int>> dp(t + 1, vector<int>(w + 1, 0));for (int i = 1; i <= t; i++){for (int j = 0; j <= w; j++){dp[i][j] = dp[i - 1][j];if(j)dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1]);dp[i][j] += (a[i] == j % 2);}}int mx = 0;for (int i = 0; i <= w; i++){mx = max(mx, dp[t][i]);}cout << mx;
}
signed main()
{//cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}
P2904 [USACO08MAR] River Crossing S - 洛谷
思路:
題目告訴我們載n頭牛要ΣM(1~n)的時間,讓我們求載完所有牛最少要多少時間
我們定義dp[i] 為運輸完前 i 頭牛所花費的最短時間
那么轉移方程就是 dp[i] = min(dp[i],dp[i - j] + sum[j]),其中sum[j]為運輸 j 頭牛耗費的時間
感覺是類完全背包問題
代碼:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endlvoid solve()
{int n, m;cin >> n >> m;vector<int> w(n+1,0),dp(n+1,1000000000);w[0] = 2 * m;for (int i = 1; i <= n; i++){cin >> w[i];w[i] += w[i - 1];}dp[0] = 0;for (int i = 1; i <= n; i++){for (int j = 1; j <= i; j++){dp[i] = min(dp[i], dp[i - j] + w[j]);}}cout << dp[n] - m;
}
signed main()
{//cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}
P2946 [USACO09MAR] Cow Frisbee Team S - 洛谷
思路:
由于我們要保證他是F的倍數,但是我們肯定不能直接開一個 0 ~ n*F 的bool數組
那我們就需要轉化了,由于我們不需要知道具體的數,我們只需要知道是否是F的倍數,所以我們可以直接開兩個維度,定義dp[i][j]為前i個數組成余F為j的方法有幾種
那么轉移方程就是 dp[i][j] += dp[i-1][j] + dp[i-1][(j -?r[i] + F) % F],這里 j -?r[i] + F % F代表沒選 r[i]之前的余數是多少,加F這個操作是為了防止其為負數,在大數取模中也可看見
代碼:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endl
const int MOD = 1e8;
void solve()
{int n, f;cin >> n >> f;vector<int> r(n + 1);vector<vector<int>> dp(n + 1, vector<int>(f+1, 0));for (int i = 1; i <= n; i++){cin >> r[i];r[i] %= f;dp[i][r[i]] = 1;}for (int i = 1; i <= n; i++){for (int j = 0; j <= f - 1; j++){//不選dp[i][j] += dp[i - 1][j];dp[i][j] %= MOD;//選dp[i][j] += dp[i - 1][(j - r[i] + f) % f];dp[i][j] %= MOD;}}cout << dp[n][0] % MOD;
}
signed main()
{//cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}
P1806 跑步 - 洛谷
思路:
我們定義dp[i][j]為跑了i圈,且最后一次跑了j圈的方案數量,那么轉移就是dp[ i ][ j ] += dp[ i - j ][ k ]
三重循環即可
代碼:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endlvoid solve()
{int n;cin >> n;vector<vector<int>> dp(n + 1, vector<int>(n+1,0));for (int i = 1; i <= n; i++){dp[i][i] = 1;}for (int i = 1; i <= n; i++){for (int j = 1; j < i; j++){for (int k = 1; k < j && j+k <= i; k++){dp[i][j] += dp[i-j][k];}}}int res = 0;for (int i = 1; i < n; i++){res += dp[n][i];}cout << res;
}
signed main()
{//cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}
P1922 女仆咖啡廳桌游吧 - 洛谷
思路:
由于要確保任意的子樹都滿足桌游和咖啡廳數量一直,所以我們可以直接看葉子節點,只要最下面滿足了,那么上面按照下面的遞推即可
首先可分配的數量為其葉子節點的數量加上自身,那么最多的可選數量就是 sum / 2,然后算出來后往上遞推到節點 1 即可
代碼:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endl
vector<vector<int>> g(100005);
vector<int> dp(100005,0);
void dfs(int son,int fa)
{int point = 1;for (auto s : g[son]){if (s == fa){continue;}if (g[s].size() == 1){point++;}else{dfs(s, son);dp[son] += dp[s];}}dp[son] += point / 2;
}void solve()
{int n;cin >> n;for (int i = 0; i < n-1; i++){int u, v;cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs(1,1);cout << dp[1];
}
signed main()
{//cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}
P12175 [藍橋杯 2025 省 Python B] 園藝 - 洛谷
思路:
因為我們要確定間隔,所以我們可以多開一維,定義dp[i][j]前i個樹中間隔為j的最長不遞減子序列
雙重循環即可
代碼:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endlvoid solve()
{int n;cin >> n;vector<int> h(n+1);for (int i = 1; i <= n; i++){cin >> h[i];}vector<vector<int>> dp(n + 1, vector<int>(n + 1, 0));for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){dp[i][j] = 1;}}int res = 0;for (int i = 2; i <= n; i++){for (int j = 1; j < i; j++){if (h[i-j] < h[i]){dp[i][j] += dp[i - j][j];res = max(res, dp[i][j]);}}}cout << res;
}
signed main()
{//cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}
P1564 膜拜 - 洛谷
思路:
這里我們可以利用一個技巧,既然要確保二者的人數差不超過m,那我們就可以視2為-1,那么只要abs(sum) <= m 即可,同時如果 abs(sum) = len 時說明這一串都是同一個數
那么定義 dp[i] 為前 i 個分割的最小數
然后按照上面說的雙重枚舉即可
代碼:
#include <iostream>
#include <algorithm>
#include<cstring>
#include <iomanip>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <utility>
#include <array>
#include <tuple>
using namespace std;
#define int long long
#define yes cout << "YES" << endl
#define no cout << "NO" << endlvoid solve()
{int n, m;cin >> n >> m;vector<int> dp(n+1,1e9),sum(n+1,0);for (int i = 1; i <= n; i++){int x;cin >> x;sum[i] = sum[i - 1] + (x == 1 ? 1 : -1);}dp[0] = 0;for (int i = 1; i <= n; i++){for (int j = 1; j <= i; j++){if (abs(sum[i] - sum[j-1]) == i-j+1 || abs(sum[i] - sum[j-1]) <= m){dp[i] = min(dp[j-1] + 1, dp[i]);}}}cout << dp[n];
}
signed main()
{//cin.tie(0)->sync_with_stdio(false);int t = 1;//cin >> t;while (t--){solve();}return 0;
}