1. 程式人生 > 實用技巧 >Codeforces #657 Problem B

Codeforces #657 Problem B

目錄

Contest Info


傳送門

Solved A B C D E F G H I J K L
8 / 13 O O Ø Ø O - Ø - - - - O
  • O 在比賽中通過
  • Ø 賽後通過
  • ! 嘗試了但是失敗了
  • - 沒有嘗試

Solutions


A. Clam and Fish

貪心模擬。

Code
// Author : heyuhhh
// Created Time : 2020/07/18 12:23:24
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run() {
    int n;
    cin >> n;
    string s;
    cin >> s;
    int ans = 0;
    int p = 0;
    int d = 0;
    for (int i = 0; i < n; i++) {
        if (s[i] == '0') {
            if (p > d) {
                --p;
                ++ans;
            } else if (d > 0) {
                --d;
                ++ans;
            }
        } else if (s[i] == '1') {
            if (p > d) {
                //make it clam and use it later
                ++d;
            } else {
                ++p;
            }
        } else {
            ++ans;
        }
    }
    ans += d;
    cout << ans << '\n';
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T; while(T--)
    run();
    return 0;
}

B. Classical String Problem

將序列的翻轉看作指標的偏移。

Code
// Author : heyuhhh
// Created Time : 2020/07/18 12:11:54
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run() {
    string s; cin >> s;
    int n = s.length();
    int q; cin >> q;
    int p = 0;
    while (q--) {
        string op;
        int x;
        cin >> op >> x;
        if (op == "M") {
            if (x > 0) {
                p = (p + x) % n;
            } else {
                p = (p + x + n) % n;
            }
        } else {
            int pos = (p + x - 1) % n;
            cout << s[pos] << '\n';
        }
    }
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

C. Operation Love

通過叉積求出有向面積判斷圖形給出的方向,之後直接check即可。

Code
// Author : heyuhhh
// Created Time : 2020/07/18 21:11:26
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run() {
    int n = 20;
    vector<double> x(n + 1), y(n + 1);
    for (int i = 0; i < n; i++) {
        cin >> x[i] >> y[i];
    }
    x[n] = x[0], y[n] = y[0];
    auto sq = [&] (double t) {
        return t * t;
    };
    vector<double> d(n);
    double tot = 0;
    for (int i = 0; i < n; i++) {
        d[i] = sqrt(sq(x[i + 1] - x[i]) + sq(y[i + 1] - y[i]) + 0.5);
        tot += x[i] * y[i + 1] - x[i + 1] * y[i];
    }
    if (tot < 0) {
        reverse(all(d));
    }
    int a, b;
    for (int i = 0; i < n; i++) {
        if ((int)(d[i] + 0.5) == 6) a = i;
        if ((int)(d[i] + 0.5) == 8) b = i;
    }
    if ((a + 2) % n == b) {
        cout << "right" << '\n';
    } else {
        cout << "left" << '\n';
    }
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T; while(T--)
    run();
    return 0;
}

D. Points Construction Problem

題意:
無限大平面內要放置\(n\)個黑點,使得有\(m\)對黑點、白點相鄰。
\(n,m\leq 200\)

思路:
顯然是一個構造題,我們需要構造出剛好符合條件的方案。
首先考慮不合法的情況:\(m\)為奇數或者\(m>4n\)顯然不合法,還有一個問題就是答案的下界。將問題轉化為周長問題,那麼面積相同的情況下,圓形的周長最小,所以下界應該是多個黑點緊湊在一起的情況。假設有\(a\)\(b\)列,那麼周長即為\(2(a+b)\),並且滿足\(a\cdot b\geq n\)。據此可以算出下界。
那麼之後直接構造,如果有\(a,b\)符合條件那麼直接輸出;
否則觀察我們拿走一個到無窮遠的地方,周長只會增加\(2\)或者\(4\),所以我們直接這樣操作就行。
最後如果周長還差\(2\),那麼我們將兩個黑點拼在一起即可。

Code
// Author : heyuhhh
// Created Time : 2020/07/19 09:35:17
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
void err(int x) {cerr << x;}
void err(long long x) {cerr << x;}
void err(double x) {cerr << x;}
void err(char x) {cerr << '"' << x << '"';}
void err(const string &x) {cerr << '"' << x << '"';}
void _print() {cerr << "]\n";}
template<typename T, typename V>
  void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
template<typename T>
  void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
template <typename T, typename... V>
  void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifdef Local
#define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define dbg(x...)
#endif
//head
const int N = 1e5 + 5;
void run() {
    int n, m;
    cin >> n >> m;
    
    int a, b;
    int Min = INF;
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= m; j++) {
            if (i * j >= n && (i - 1) * j < n && i * (j - 1) < n) {
                if (2 * (i + j) < Min) {
                    Min = 2 * (i + j);
                    a = i, b = j;
                }
                if (2 * (i + j) == m) {
                    a = i, b = j;
                    goto nxt;
                }
            }
        }
    } nxt:;
    if (m & 1 || m > 4 * n || m < 2 * (a + b)) {
        cout << "No" << '\n';
        return;
    }
    dbg(a, b);
    vector<pii> ans;
    int tot = 2 * (a + b);
    int r = n;
    for (int i = 1; i <= a && r; i++) {
        for (int j = 1; j <= b && r; j++, --r) {
            ans.push_back(MP(i, j));
        }
    }
    vector<pii> res;
    int x = 1000000, y = 100000000;
    while (sz(ans) > 1 && m - tot >= 4) {
        pii now = ans.back();
        ans.pop_back();
        if (now.se == 1 || now.fi == 1) {
            tot += 2;
        } else {
            tot += 4;
        }
        res.push_back(MP(x, y));
        x += 2;
    }
    assert(m - tot <= 2);
    if (m - tot >= 2) {
        pii now = ans.back();
        ans.pop_back();
        if (now.fi == 1 || now.se == 1) {
            res.push_back(MP(x, y));
        } else {
            res.push_back(MP(now.fi - 1, b + 1));
        }
    }
    cout << "Yes" << '\n';
    for (auto it : res) {
        cout << it.fi << ' ' << it.se << '\n';
    }
    for (auto it : ans) {
        cout << it.fi << ' ' << it.se << '\n';
    }
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T; while(T--)
    run();
    return 0;
}

E. Two Matchings

考慮將陣列升序排序,那麼如果只找一個序列的話顯然\((1,2),(3,4),\cdots\)這樣進行匹配,我們將其看作\((-,+,-,+,-,+,...,-,+)\)
對於第二個序列,比較直觀的方法是\((-,-,+,-,+,...,+,+)\)。會發現此時答案為\(2(a_n-a_1)\)
但這並不是最優解,觀察我們可以交換第二個序列中某個\(+\)和前面一個\(-\)的順序,這樣能使得答案最小。
並且有一個這樣的性質,對於\(i,i+1,i+2,i+3\)這四個位置,如果我們交換了\(i+2,i+3\),那麼不能交換\(i,i+1\)。並且也不能交換\(2,3\)以及\(n-2,n-1\)
所以根據這一點直接\(dp\)就行。
詳見程式碼:

Code
// Author : heyuhhh
// Created Time : 2020/07/18 13:37:37
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run() {
    int n;
    cin >> n;
    vector<ll> a(n);
    ll ans = 0;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    sort(all(a));
    for (int i = 1; i < n; i += 2) {
        ans += a[i] - a[i - 1];
    }
    vector<ll> dp(n);
    dp[0] = -a[0];
    dp[2] = -a[0] - a[1] + a[2];
    for (int i = 4; i < n - 1; i += 2) {
        dp[i] = dp[i - 2] + a[i] - a[i - 1];
        if (i < n - 2) {
            dp[i] = min(dp[i], dp[i - 4] - a[i - 3] + a[i - 2] + a[i - 1] - a[i]);
        }
    }
    ans += dp[n - 2] + a[n - 1]; 
    cout << ans << '\n';
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T; while(T--)
    run();
    return 0;
}

F. Fraction Construction Problem

題意:
構造題。
給出\(a,b\leq 2\cdot 10^6\)
然後找到\(c,d,e,f\),滿足:

  • \(\frac{c}{d}-\frac{e}{f}=\frac{a}{b}\);
  • \(d<b,f<b\);
  • \(1\leq c,e\leq 4\cdot 10^{12}\).

無解則輸出-1。

思路:
\(g=gcd(a,b)\),首先注意到如果\(g>1\)那麼就win了,方案很容易構造。
接下來就只用考慮\(g=1\)的情況,大體思路就是構造\(d,f\)使得\(d\cdot f=b\),之後再解一個\(cf-ed=a\)的二元一次方程。
方程有解則需要保證\(gcd(d,f)|a\),又因為\(d\cdot f = b,gcd(a,b)=1\)。也就是我們找的\(d,f\)一定是互質的,否則就不可能存在解。
所以找到這樣的兩個數過後用exgcd解一下方程就行。
但這裡我有個問題,就是在exgcd的過程中先乘\(c\)會wa,後乘\(c\)就A了,但實際上兩種寫法都沒問題,不知道是哪裡的原因...

Code
// Author : heyuhhh
// Created Time : 2020/07/18 15:52:18
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e6 + 5;
const ll MAX = 4e18;
    
int v[N], prime[N];
int num;
void Euler() {
    v[1] = 1;
    for(int i = 2; i < N; i++) {
        if(v[i] == 0) {
            v[i] = i;
            prime[++num] = i;
        }
        for(int j = 1; j <= num && prime[j] * i < N; j++) {
            v[prime[j] * i] = prime[j] ;
        }
    }
}
    
void exgcd(ll a, ll b, ll &x, ll &y) {
    if(b == 0) {
        x = 1, y = 0;
        return ;
    }
    exgcd(b,a%b,x,y);
    ll z = x ;
    x = y;
    y = z - y * (a / b);
}
//ax + by = c
ll calc(ll a, ll b, ll c) {
    ll x, y;
    ll g = __gcd(a, b);
    assert(g == 1);
    // g = 1
    a /= g, b /= g, c /= g;
    exgcd(a, b, x, y);
    assert(x <= MAX / c);
    // x *= c;
    x = (x % b + b) % b;
    if (x == 0) x += b;
    x *= c;
    return x;
}
    
void run() {
    int a, b;
    cin >> a >> b;
    int g = __gcd(a, b);
    if (g == 1) {
        // c / d - e / f = a / b
        // cf - ed = a
        if (v[b] == b) {
            cout << -1 << ' ' << -1 << ' ' << -1 << ' ' << -1 << '\n';
        } else {
            int f = 1;
            int x = b;
            while (x % v[b] == 0) {
                x /= v[b];
                f *= v[b];
            }
   
            if (x == 1) {
                cout << -1 << ' ' << -1 << ' ' << -1 << ' ' << -1 << '\n';
                return;
            }
               
            int d = b / f;
            ll c = calc(f, d, a);
            ll e = (c * f - a) / d;
 
            if (e < 0) {
                e = -e;
            }
   
            assert(e > 0 && c > 0 && c <= 1000000000000 && e <= 1000000000000);
            cout << c << ' ' << d << ' ' << e << ' ' << f << '\n';        
        }
    } else {
        a /= g, b /= g;
        int t = a / b;
        int c = t + 1, d = 1;
        ll e = b - a % b, f = b;
        cout << c << ' ' << d << ' ' << e << ' ' << f << '\n';
    }
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    Euler();
    int T; cin >> T; while(T--)
    run();
    return 0;
}

G. Operating on a Graph

題意:
給出一張\(n\)個點,\(m\)條邊的無向圖,現在每個點初始顏色為\(i\)
現在有\(q\)次操作,每次操作選擇一個顏色為\(i\)的集合,並且將其周圍的點顏色都染為\(i\)
最後問\(q\)次操作結束過後每個點的顏色。

思路:
考慮每個點至多會被染一次色,所以可以直接模擬。
但模擬涉及到點集的合併,這一點會導致複雜度爆炸。
然後合併的時候搞個連結串列其實就行了,因為並不需要隨機訪問中間某個點,並且連結串列可以\(O(1)\)合併。

Code
// Author : heyuhhh
// Created Time : 2020/07/20 09:41:10
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 8e5 + 5;

int n, m;
int f[N];
list<int> lists[N];
vector<int> G[N];

void init() {
    for (int i = 0; i < n; i++) {
        f[i] = i;
        G[i].clear();
        lists[i].clear();
        lists[i].push_back(i);
    }
}

int find(int x) {
    return f[x] == x ? f[x] : f[x] = find(f[x]);
}

void Union(int x, int y) {
    int fx = find(x), fy = find(y);
    if (fx != fy) {
        f[fy] = fx;
        lists[fx].splice(lists[fx].end(), lists[fy]);
    }
}

void run() {
    cin >> n >> m;
    init();
    for (int i = 0; i < m; i++) {
        int u, v; 
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    int q;
    cin >> q;
    while (q--) {
        int o;
        cin >> o;
        if (find(o) != o) continue;
        int size = sz(lists[o]);
        for (int i = 0; i < size; i++) {
            int u = lists[o].front();
            for (auto v : G[u]) {
                Union(o, v);
            }
            lists[o].pop_front();
        }
    }
    for (int i = 0; i < n; i++) {
        cout << find(i) << ' ';
    }
    cout << '\n';
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T; while(T--)
    run();
    return 0;
}

L. Problem L is the Only Lovely Problem

簽到。

Code
// Author : heyuhhh
// Created Time : 2020/07/18 12:01:57
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run() {
    string s;
    cin >> s;
    if (s.length() < 6) {
        cout << "ugly" << '\n';
        return;
    }
    for (int i = 0; i < 6; i++) {
        if (s[i] >= 'A' && s[i] <= 'Z') {
            s[i] = s[i] - 'A' + 'a';
        }
    }
    string t = s.substr(0, 6);
    if (t == "lovely") {
        cout << "lovely" << '\n';
    } else {
        cout << "ugly" << '\n';
    }
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}