1. 程式人生 > >CF變紅之路_Educational Codeforces Round 53 (Rated for Div. 2)

CF變紅之路_Educational Codeforces Round 53 (Rated for Div. 2)

昨天打的一場比賽,開始AB題出的很順,C題不會做(沒想到二分的思路),D題出的較慢,一共出了3道題排名1003。今天又重新做了C題發現思路雖然很巧妙,但也是正常的二分思路。

A

簽到題,看懂題就會寫。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 100;
char s[maxn];
int main() {
    int n;
    cin >> n;
    scanf("%s", s);
    int flag = 1;
    for(int i = 1; i < n;
i++) { if(s[i] != s[i-1]) { cout << "YES" << endl; cout << s[i-1] << s[i] << endl; flag = 0; break; } } if(flag) cout << "NO" << endl; return 0; }

B

用set維護已經拿出的書,在set裡的一律輸出0然後再找下一個不在set的,遍歷的過程中放到set中。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 100;
int a[maxn];
int b[maxn];
int main() {
   int n;
   cin >> n;
   for(int i = 1; i <= n; i++) {
       scanf("%d", &a[i]);
   }
   for(int i = 1; i <= n; i++) {
       scanf("%d", &b[i]);
   }
   set<
int> st; int cur = 1; for(int i = 1; i <= n; i++) { int tmp = b[i]; if(st.count(tmp)) { printf("0 "); continue; } int ret = 1; while(a[cur] != tmp) { st.insert(a[cur]); cur++; ret++; } cur++; printf("%d ", ret); } return 0; }

C

題目大意:給出一個字串,其中每個字元代表移動的方向,起點是原點,然後給出一個座標,問如果無需修改其中的操作就能到達座標的話輸出0如果在不增減的條件下修改不能到的話輸出-1,否則輸出修改最小的區間的大小。
思路:輸出的0和-1兩種情況直接特判就行,然後二分猜最小區間的大小然後放判斷,判斷的方法也很巧妙,區間和的思路可以極大的減少重複計算量。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = (int)2e5 + 100;

char s[maxn];
ll sx[maxn], sy[maxn];

ll getSum(ll l, ll r, ll* a) {    // 求區間和
    return a[r] - a[l - 1];
}

bool ok(ll x, ll y, ll n) {     // 判斷操作n次能否位移量為(x,y)
    x = abs(x);
    y = abs(y);
    return x + y <= n && ((x + y) & 1) == (n & 1);
}

bool judge(ll m, ll n, ll x, ll y) {
    bool flag = false;
    for (ll i = 1; i + m - 1 <= n; i++) {
        ll xx = sx[n] - getSum(i, i + m - 1, sx);
        ll yy = sy[n] - getSum(i, i + m - 1, sy);
        flag |= ok(x - xx, y - yy, m);
        if (flag) return true;
    }
    return false;
}

int main() {
    ll n, x, y;
    scanf("%lld%s%lld%lld", &n, s + 1, &x, &y);
    sx[0] = sy[0] = 0;
    for (int i = 1; i <= n; i++) {
        sx[i] = sx[i - 1];
        sy[i] = sy[i - 1];
        sx[i] += (s[i] == 'R');
        sx[i] -= (s[i] == 'L');
        sy[i] += (s[i] == 'U');
        sy[i] -= (s[i] == 'D');
    }
    if (sx[n] == x && sy[n] == y) {
        cout << 0 << endl;
        return 0;
    }
    if (!ok(x, y, n)) {
        cout << -1 << endl;
        return 0;
    }
    ll l = 0, r = n;
    while (r - l > 1) {
        ll m = (l + r) >> 1;
        if (judge(m, n, x, y)) {
            r = m;
        } else {
            l = m;
        }
    }
    cout << r << endl;
    return 0;
}

D

由於T很大,直接for迴圈模擬的話必定超時,可以先求和然後判斷能走幾圈(在不跳的情況下),如果不能不跳,即和大於擁有的金額,那麼遍歷一次,和減去不能支付的,在判斷能走幾圈,迴圈的終止條件是所有的都不能支付。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 100;
ll v[maxn];
bool vis[maxn];
bool cmp(ll a, ll b) {
    return a > b;
}
int main() {
    ll n,have;
    cin >> n >> have;
    ll sum = 0;
    for(ll i = 0; i < n; i++) {
        scanf("%lld", &v[i]);
        sum += v[i];
    }
    ll cnt = n;
    ll ans = 0;
    memset(vis, false, sizeof vis);
    while(cnt) {
        if(sum <= have) {
            ans += (have / sum)*cnt;
            have -= (have / sum) * sum;
        }
        for(int i = 0; i < n; i++) {
            if(vis[i]) continue;
            if(v[i] > have) {
                cnt--;
                vis[i] = true;
                sum-=v[i];
                continue;
            }
            else {
                have -= v[i];
                ans++;
            }
        }
    }
    cout << ans << endl;
    return 0;
}