Codeforces Round #608 (Div. 2)


傳送門

A. Suits

簽到。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2019/12/15 17:16:33
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int a[4], e, f;
 
void run(){
    for(int i = 0; i < 4; i++) cin >> a[i];
    cin >> e >> f;
    int ans = 0;
    if(e > f) {
        int d = min(a[0], a[3]);
        ans += d * e;
        a[3] -= d;
        d = *min_element(a + 1, a + 4);
        ans += d * f;
    } else {
        int d = *min_element(a + 1, a + 4);
        ans += d * f;
        a[3] -= d;
        d = min(a[0], a[3]);
        ans += d * e;
    }
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

B. Blocks

因為最終只有可能全為黑或全為白,那么分兩種情況進行翻轉即可。
一開始只考慮了一種情況然后FST了...話說,如果我一開始考慮的是另一種情況進行翻轉,樣例都過了,那樣的話就應該反應過來需要考慮兩種情況了吧= =過題還是要看運氣hhh

Code
/*
 * Author:  heyuhhh
 * Created Time:  2019/12/15 17:21:42
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 200 + 5;
 
char s[N], t[N];
int n;
 
void run(){
    cin >> (s + 1);
    strcpy(t + 1, s + 1);
    vector <int> ans;
    for(int i = 1; i < n; i++) {
        if(s[i] != 'W') {
            s[i] = 'W';
            s[i + 1] = (s[i + 1] == 'W' ? 'B' : 'W');
            ans.push_back(i);
        }   
    }
    if(s[n] == 'W') {
        cout << sz(ans) << '\n';
        for(auto it : ans) cout << it << ' ';
        cout << '\n'; 
        return;
    } 
    strcpy(s + 1, t + 1);
    ans.clear();
    for(int i = 1; i < n; i++) {
        if(s[i] != 'B') {
            s[i] = 'B';
            s[i + 1] = (s[i + 1] == 'B' ? 'W' : 'B');
            ans.push_back(i);
        }   
    }
    if(s[n] == 'B') {
        cout << sz(ans) << '\n';
        for(auto it : ans) cout << it << ' ';
        cout << '\n'; 
        return;
    }
    cout << -1 << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n) run();
    return 0;
}

C. Shawarma Tent

題意:
給出一個點\((s_x,s_y)\),再給出\(n\)個點\((x_i,y_i)\)
現在找到一個點\((x_0,y_0)\),使得\(cnt\)最大。每當有一個點\((x_i,y_i)\)到點\((s_x,s_y)\)的最短曼哈頓距離經過\((x_0,y_0)\)時,\(cnt\)++。
最后輸出\(cnt\)\((x_0,y_0)\)

思路:
顯然,所有最短曼哈頓路徑必然存在於一個矩形之內。
那么我們直接將所有以\((s_x,s_y),(x_i,y_i)\)為頂點的矩形畫出來即可發現最優位置只可能存在於\((s_x,s_y)\)的四個方向上。
所以直接統計在哪個方向上最優即可。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2019/12/15 17:28:16
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
int n, sx, sy;
int d[4];
 
void run(){
    for(int i = 1; i <= n; i++) {
        int x, y; cin >> x >> y;
        if(x > sx) ++d[0];
        else if(x < sx) ++d[1];
        if(y > sy) ++d[2];
        else if(y < sy) ++d[3];   
    }
    int mx = *max_element(d, d + 4);
    cout << mx << '\n';
    if(d[0] == mx) {
        cout << sx + 1 << ' ' << sy << '\n';
    } else if(d[1] == mx) {
        cout << sx - 1 << ' ' << sy << '\n';
    } else if(d[2] == mx) {
        cout << sx << ' ' << sy + 1 << '\n';
    } else {
        cout << sx << ' ' << sy - 1 << '\n';
    }   
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n >> sx >> sy) run();
    return 0;
}

D. Portals

題意:
現在有\(n\)個堡壘,要從\(1\)\(n\)逐個攻破。
起初帶有\(k\)個士兵,每占領一個堡壘需要\(a_i\)的士兵,可以在每座堡壘中招募\(b_i\)的士兵。
在占領堡壘的過程中不會發生傷亡。每座堡壘有一個價值\(c_i\),若派遣一個士兵去防守,那么可以獲得\(c_i\)的價值。
防守的方式有兩種:

  • 占領一座堡壘之后可以就留下一名士兵;
  • 圖中存在某些單向通道\(u\rightarrow v,u>v\),當你在\(u\)時可以派遣一名士兵前往\(v\)(每名士兵只能穿越通道最多一次)。

現在問能否占領所有的堡壘,若能,最大能獲得多少的價值。

思路:
這題初看是個模擬題,仔細想其實不是個模擬題,...帶有一些\(dp\)的性質在里面。
首先有個觀察:

  • 如果我要防守\(i\)堡壘,那么我肯定是在最后時刻派遣士兵過來最優。

正確性顯然,如果我們在較早時刻派遣士兵進行防守,那么我們也可以將那個士兵留在后面再派遣。
那么圖中現在只剩下最多\(n\)條邊。

然后就考慮\(dp:\)\(dp[i][j]\)表示當前在第\(i\)號堡壘,帶有\(j\)個士兵能獲得的最大價值。
因為招募這個條件有點特殊,我們不能就在\(i\)這個位置由\(j\rightarrow j+b_i\)轉移,所以可以考慮再加一維狀態表示招募與否,或者直接向\(i+1\)進行轉移。
可以發現后者並不影響結果。因為即便得到當前的答案,后面也會繼承當前的結果。
那么一種情況就是招募士兵:\(dp[i][j]\rightarrow dp[i+1][j+b_i]\)
另一種情況就是派遣士兵回防:\(dp[i+1][j]\rightarrow dp[i+1][j-1]\)
需要注意兩個的順序不能顛倒。

最終時間復雜度為\(O(5000\cdot n+n)\)

Code
/*
 * Author:  heyuhhh
 * Created Time:  2019/12/16 10:45:39
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5000 + 5;

int n, m, k;
int a[N], b[N], c[N];
int latest[N];
int dp[N][N];

void run(){
    for(int i = 1; i <= n; i++) {
        cin >> a[i] >> b[i] >> c[i];
    }
    for(int i = 1; i <= n; i++) latest[i] = i;
    for(int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        latest[v] = max(latest[v], u);
    }
    for(int i = 0; i <= n + 1; i++) {
        for(int j = 0; j < N; j++) {
            dp[i][j] = -INF;
        }
    }
    dp[1][k] = 0;
    for(int i = 1; i <= n; i++) {
        vector <int> costs;
        for(int j = 1; j <= i; j++) {
            if(latest[j] == i) costs.push_back(c[j]);
        }
        sort(all(costs));
        reverse(all(costs));
        for(int j = 0; j < N; j++) {
            if(j >= a[i] && dp[i][j] >= 0) {
                dp[i + 1][j + b[i]] = max(dp[i + 1][j + b[i]], dp[i][j]);   
            }
        }
        for(auto x : costs) {
            for(int j = 0; j < N; j++) {
                if(dp[i + 1][j] >= 0) {
                    dp[i + 1][j - 1] = max(dp[i + 1][j - 1], dp[i + 1][j] + x);   
                }
            }
        }
    }
    int ans = -1;
    for(int i = 0; i < N; i++) ans = max(ans, dp[n + 1][i]);
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n >> m >> k) run();
    return 0;
}

E. Common Number

題意:
定義函數\(f(x):\)

\[f(x)=\left\{ \begin{aligned} \frac{x}{2}, \ \ \ &if\ x\ is\ even\\ x-1 \ \ \ &otherwise \end{aligned} \right. \]

同時定義\(path(x)\)\(f(x),f(f(x)),\cdots\)的所有值。
現在要找最大的一個\(y\),滿足\(1\)~\(n\)中,不少於\(k\)個數,有\(y\in path(x_i)\)

思路:
觀察得到若最終答案\(y\)為奇數時,合法的\(x\)為:\(y,\ \ 2\cdot y,2\cdot y+1,\ \ 2^2\cdot y,2^2\cdot y+1,2^2\cdot y+2,2^2\cdot y+3,\ \cdots\)
同樣能找到答案為偶數時的序列。
那奇數情況舉例,若答案為奇數時,那么最終個數為\(1+2+4+\cdots\),同時對應的數以\(y\cdot 2^0,y\cdot 2^1,\cdots\)為起點。
那么只需要找到最大的\(r,2^r\leq n\),再計算出總長度即可得到答案為某個奇數時滿足條件的\(x\)個數。
顯然問題具有單調性,所以二分答案即可。

因為偶數的情況和奇數的情況有點小區別,所以分奇偶兩種情況二分,最后取最大值即可。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2019/12/15 17:45:31
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
 
ll n, k;
 
ll qpow(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a;
        a = a * a; 
        b >>= 1;   
    }
    return ans;   
}
 
bool chk(ll x) {
    ll cnt = 0;
    if(x & 1) {
        ll now = x, tmp = 1 + (x % 2 == 0);
        int k = 0;
        for(int i = 0; i < 61; i++) {
            if(now > n) {
                k = i - 1; now /= 2; tmp /= 2; cnt -= tmp;
                break;   
            }
            cnt += tmp;
            now *= 2; tmp *= 2; 
        }
        ll d = min(n - now + 1, tmp);
        cnt += d;
    } else {
        ll now = x, tmp = 2;
        int k = 0;
        for(int i = 0; i < 61; i++) {
            if(now > n) {
                k = i - 1; now /= 2; tmp /= 2; cnt -= tmp;
                break;   
            }
            cnt += tmp;
            now *= 2; tmp *= 2; 
        }
        ll d = min(n - now + 1, tmp);
        cnt += d;
    }   
    return cnt >= k;
}
 
void run(){
    ll l = 2, r = n + 1, mid;
    ll ans = 1;
    while(l < r) {
        mid = (l + r) >> 1;
        if(mid & 1) ++mid;
        if(mid >= r) mid -= 2;
        if(mid < l) break;
        if(chk(mid)) {
            ans = mid;
            l = mid + 2;
        } else r = mid - 1;
    }
    l = 1, r = n + 1;
    while(l < r) {
        mid = (l + r) >> 1;
        if(mid % 2 == 0) ++mid;
        if(mid >= r) mid -= 2;
        if(mid < l) break;
        if(chk(mid)) {
            ans = max(ans, mid);
            l = mid + 2;
        } else r = mid - 1;
    }
    cout << ans << '\n';
}
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n >> k) run();
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM