靈茶之貪心模擬01

gebeng發表於2024-03-26

靈茶之貪心模擬01

題目連結

https://codeforces.com/problemset/problem/1443/B

題目大意

輸入 T(≤\(10^5\)) 表示 T 組資料。所有資料的字串長度之和 ≤ \(10^5\)

每組資料輸入 a(1≤a≤1000) b(1≤b≤1000) 和長度不超過 \(10^5\) 的 01 字串。

你可以花費 a,把一段連續的 1 變成 0。

也可以花費 b,把一個 0 變成 1。

上述兩種操作可以執行任意次。 輸出把所有 1 都變成 0 的最小花費。

題目思路

  • 如果沒有1,就直接輸出0
  • 考慮這樣的一部分:1110001111
    • 我們有兩種方案
    • ①將兩邊連續的1花費a變成0,總花費為2a
    • ②將中間0花費 k * b 變成1,在花費a1變成0,總花費為 kb + a
    • 比較方案①與方案②,自然是選擇總花費最小的方案了
  • 我們只需從左往右使用雙指標[left,right],找到兩段 1中間的那串0,考慮將這兩段1合併成一段1的最小花費,再加上最後合併成的那一連串1的花費a即可

程式碼

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n,a,b,t;
void solve() {
    string s;
    cin >> a >> b;cin >> s;
    n = (int)s.size();
    // s 裡 不 包 含 0!
    if(s.find('1') == string::npos) {
        cout << 0 << '\n';
        return;
    }
    int ans = a;
    int right = 0,left;
    while(right < n){
        char x = s[right];
        left = right;
        while(right < n && s[right] == x) ++right;
        if(x == '0' && right < n){
            if(left == 0) continue;
            ans += min(b * (right - left),a);
        }
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> t;
    for (int _ = 0; _ < t; _++) solve();
    return 0;
}

相關文章