- 小訓練
- T219724 最大子段和
我本來以為很簡單的一道題,用字首和去找,但是我粗心了一個寫錯了後面重新寫過了,但是,後面發現是一個類似於動態規劃的演算法題
Kadane 演算法
專門求這種最大子段和問題,時間複雜度為O(n)
Kadane演算法(Kadane’s Algorithm)是一種用於解決最大子陣列和問題(Maximum Subarray Sum Problem)的動態規劃演算法。該問題的目標是在給定整數陣列中找到一個連續的子陣列,使其元素之和最大。Kadane演算法的時間複雜度為O(n),其中n是陣列的長度,因此它是解決這個問題的高效方法。
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
int current_sum = 0;
int max_sum = 0;
int x;
for (int i = 0; i < n; i++) {
cin >> x;
current_sum = max(x, current_sum + x);
max_sum = max(max_sum, current_sum);
}
cout << max_sum << endl;
return 0;
}
字首和暴力
#include <bits/stdc++.h>
using namespace std;
int v[100861];
int prefix[10005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>v[i],prefix[i]+=prefix[i-1]+v[i];
int ans=v[1];
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
if(prefix[j]-prefix[i-1]>ans){
ans=prefix[j]-prefix[i-1];
}
}
}
if(ans>=0)
cout<<ans;
else
cout<<0;
}
- Technical Support
用棧存Q,如果遇到不是Q那麼彈出Q,最後看stack裡面還有沒有Q就行
#include <bits/stdc++.h>
using namespace std;
using ll =long long;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
stack<int>st;
for(int i=1;i<=n;i++){
char b;
cin>>b;
if(b=='Q')st.emplace(1);
else {
if(st.size()){
st.pop();
}
}
}
if(st.size()>0)cout<<"No\n";
else cout<<"Yes\n";
}
}
- 動態規劃專項訓練
- 區間dp
- 凸多邊形的劃分
這道題聽不懂思路,但是可以去記住這類題型,多邊形的劃分三角形頂點的權值乘積和至少為多少。
我們使用vector來儲存權值和DP陣列,因為乘積可能會很大。
外層迴圈len表示當前處理的區間長度,從3開始遞增到n。
中層迴圈i表示區間的起點,範圍是1到n-len+1。
內層迴圈k用於嘗試所有可能的分割點。
狀態轉移方程在內層迴圈中實現,我們計算分割點k將區間[i,j]分成[i,k]和[k,j]兩部分後的總乘積和,並與當前dp[i][j]比較,取最小值。
最終結果儲存在dp[1][n]中。
#include <iostream>
#include <vector>
#include <climits>
#include <string>
using namespace std;
// 用於輸出 __int128 型別的函式
string to_string(__int128 num) {
if (num == 0) return "0";
string s;
while (num) {
s = char(num % 10 + '0') + s;
num /= 10;
}
return s;
}
// 用於輸入 __int128 型別的函式
__int128 read() {
__int128 x = 0;
int f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
int main() {
int n;
cin >> n;
vector<__int128> w(n + 1);
for (int i = 1; i <= n; i++) {
w[i] = read();
}
vector<vector<__int128>> dp(n + 1, vector<__int128>(n + 1, 0));
for (int len = 3; len <= n; len++) {
for (int i = 1; i + len - 1 <= n; i++) {
int j = i + len - 1;
dp[i][j] = (__int128)1 << 126; // 一個非常大的數
for (int k = i + 1; k < j; k++) {
__int128 temp = dp[i][k] + dp[k][j] + w[i] * w[k] * w[j];
dp[i][j] = min(dp[i][j], temp);
}
}
}
cout << to_string(dp[1][n]) << endl;
return 0;
}
- 田忌賽馬
這道題dp可以貪心去做
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 10005;
int a[N], b[N];
signed main() {
ios_base::sync_with_stdio(false); cin.tie(0);
int n; cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
cin >> b[i];
sort(a + 1, a + 1 + n, greater<>());
sort(b + 1, b + 1 + n, greater<>());
int la = 1, ra = n, lb = 1, rb = n, cnt = 0;
for (int i = 1; i <= n; i++) {
if (a[la] > b[lb]) {
cnt++;
la++, lb++;
}
else if (a[ra] > b[rb]) {
cnt++;
ra--, rb--;
}
else if (a[ra] < b[lb]) {
cnt--;
ra--, lb++;
}
}
int ans = cnt * 200;
cout << ans << endl;
}
dp做法,區間dp,每一次齊王都是派出第k大的數,但是田忌不是,田忌如果想要最大那麼一開始選擇的答案受後面選擇的影響,每次選擇的k給區間是任意的
//dp[i][j] = max(dp[i+1][j]+cost(i,k), dp[i][j-1]+cost(j,k));
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 10001;
int n;
int dp[maxn][maxn];
int tian[maxn];
int qi[maxn];
int cost(int tian_pos, int qi_pos) {
if (tian[tian_pos]>qi[qi_pos]) return 200;
if (tian[tian_pos]<qi[qi_pos]) return -200;
if (tian[tian_pos]==qi[qi_pos]) return 0;
return 0;
}
signed main() {
cin>>n;
for (int i=1;i<=n;i++) {
cin>>tian[i];
}
for (int i=1;i<=n;i++) {
cin>>qi[i];
}
sort(qi+1, qi+1+n);
sort(tian+1, tian+1+n);
for (int len = 1;len<=n;len++) {
for (int l=1;l+len-1<=n;l++) {
int r = l+len-1;
int k = len-1+1;
dp[l][r] = max(dp[l+1][r]+cost(l, k), dp[l][r-1]+cost(r,k));
}`
}
cout<<dp[1][n];
return 0;
}
- 多個不相交子段和問題
狀態轉移 ,f[i][j]表示前i個數(第i個數必須取)組成j個不相交子段所能取得的最大和
f[i][j]= max(f[i-1]+a[i],f[k][j-1]+a[i])