A. ?UPC

模拟

代码实现
print(input()[0]+'UPC')

B. Heavy Snake

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n, d;
    cin >> n >> d;
    
    vector<int> t(n), l(n);
    rep(i, n) cin >> t[i] >> l[i];
    
    for (int k = 1; k <= d; ++k) {
        int ans = 0;
        rep(i, n) {
            int w = t[i]*(l[i]+k);
            ans = max(ans, w);
        }
        cout << ans << '\n';
    }
    
    return 0;
}

C. Various Kagamimochi

二分或双指针

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

int main() {
    int n;
    cin >> n;
    
    vector<int> A(n);
    rep(i, n) cin >> A[i];
    
    ll ans = 0;
    rep(b, n) {
        int r = upper_bound(A.begin(), A.begin()+b, A[b]/2) - A.begin();
        ans += r;
    }
    
    cout << ans << '\n';
    
    return 0;
}

D. Coming of Age Celebration

考虑实现以下功能的数据结构:

  • 加入一个数
  • 将集合中的所有数 -1
  • 将集合中的 0 删除
  • 查询集合的大小

可以发现用小根堆就能做,时间复杂度为 \(O(n\log n)\)

也有一种 \(O(n)\) 做法

可以考虑每个外星人到哪一年就不需要再送石头了

具体可以维护变量 \(S\) 表示到目前为止已经有 \(S\) 个成年外星人需要送石头,再开一个 \(R\) 数组用来记录第 \(i\) 年之后不需要再送石头的成年外星人的人数

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

int main() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    int s = 0;
    vector<int> r(n);
    rep(i, n) {
        a[i] += s;
        int num = min(a[i], n-i-1);
        a[i] -= num;
        s++;
        r[i+num]++;
        
        s -= r[i];
    }
    
    rep(i, n) cout << a[i] << ' ';
    
    return 0;
}

E. Simultaneous Kagamimochi

二分出 \(k\)
对于判定是一种贪心,选择最左边 \(k\) 个放在蛋糕塔的上方,再将最右边的 \(k\) 个放在蛋糕塔的下方,然后每个上方的蛋糕选择下方还没被匹配的大小最小的进行配对
也可以双指针,左边一半放上方,右边一半放下方

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

int main() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    int m = n/2, j = m;
    int ans = 0;
    rep(i, m) {
        while (j < n and a[i]*2 > a[j]) j++;
        if (j == n) break;
        ans++;
        j++;
    }
    
    cout << ans << '\n';
    
    return 0;
}

F. Dangerous Sugoroku

\(B \leqslant R-L+1\) 时显然无解
先特殊处理一下 \(A=B\) 时的情况:可以发现每次走到的格子都是 \(1+Ak, k = 1, 2, \cdots\),如果可以走进 \([L, R]\) 中的格子,显然无解,另外如果 \(N-1\) 如果不是 \(A\) 的倍数也无解
对于一般情况可以矩阵快速幂优化dp,卡卡常就过了

再来考虑一下正经做法

我们可以先将这 \(N\) 个格子分成若干个只有好格子或只有坏格子的长条,不妨简单将前者记为好块,后者记为坏块
对于每个好块,我们只关心它后面 \(B\) 个格子能否到达
如果好块的长度大于 \(A^2\),且如果以上一个坏块为右端点,在它左边 \(B-1\) 个格子以内没有好格子到达的话,那么当前好块的最后 \(B\) 个好格子一定也就不会到达,也就更不可能到达第 \(N\) 个格子了;否则,最后 \(B\) 个好格子一定都会到达
对于其他情况,利用前 \(B-A+1\) 个格子的状态对好块正常转移即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

bool solve() {
    ll n; int m, a, b;
    cin >> n >> m >> a >> b;
    
    vector<ll> l(m), r(m);
    rep(i, m) cin >> l[i] >> r[i];
    rep(i, m) l[i]--;
    
    if (a == b) {
        rep(i, m) {
            ll x = (r[i]-1)/a*a;
            if (l[i] <= x) return false;
        }
        if ((n-1)%a) return false;
        return true;
    }
    
    vector<int> dp(b);
    dp[0] = 1;
    ll i = 0;
    l.push_back(n); r.push_back(n); m++;
    rep(j, m) {
        ll w = l[j]-i-1;
        if (w > a*a) {
            if (dp == vector<int>(b, 0)) return false;
            dp = vector<int>(b, 1);
        }
        else {
            rep(k, w) {
                dp.insert(dp.begin(), 0);
                for (int x = a; x <= b; ++x) dp[0] |= dp[x];
                dp.pop_back();
            }
        }
        
        w = r[j]-l[j];
        if (w >= b) return false;
        rep(k, w) {
            dp.insert(dp.begin(), 0);
            dp.pop_back();
        }
        
        i = r[j]-1;
    }
    
    return dp[0] == 1;
}

int main() {
    if (solve()) puts("Yes");
    else puts("No");
     
    return 0;
}

G. Simultaneous Kagamimochi 2

还是二分 \(k\)
\(w = r-l+1-k\)
对于 \(0 \leqslant i < k\),都应成立 \(2A_{l+i} \leqslant A_{l+w+i}\)
再令 \(X_i\) 表示使得 \(2A_i \leqslant A_j\) 成立的最小的 \(j\)
那么就有 \(X_{l+i} \leqslant l+w+i\),变形得到 \(X_{l+i} - (l+i) \leqslant w\)
\(Y_i = X_i - i\)
我们只需判定是否成立 \(\max(Y_l, \cdots, Y_{l+k-1}) \leqslant w\) 即可
对于左边的式子可以用st表或线段树来加速

代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int op(int a, int b) { return max(a, b); }
int e() { return 0; }

int main() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    vector<int> y(n);
    {
        int j = 0;
        rep(i, n) {
            while (j < n and a[i]*2 > a[j]) j++;
            y[i] = j-i;
        }
    }
    segtree<int, op, e> rmq(y);
    
    int q;
    cin >> q;
    rep(qi, q) {
        int l, r;
        cin >> l >> r;
        --l;
        
        int ac = 0, wa = (r-l)/2+1;
        while (abs(ac-wa) > 1) {
            int wj = (ac+wa)/2;
            bool ok = rmq.prod(l, l+wj) <= r-l-wj;
            if (ok) ac = wj; else wa = wj;
        }
        cout << ac << '\n';
    }
    
    return 0;
}