Contestant. Rank 1755. Rating +54.

A. Lame King

题意

给定一个坐标系,其中 \(x \in [-100, 100], y \in [-100, 100]\)。给定一个坐标 \([s, t]\),输出按规定从 \([0, 0]\) 走到 \([s, t]\) 需要的最短时间。

规定若需要连续从相同方向移动,需要间隔一秒。

思路

首先,若我们需要一直向右,那么停留一秒绝对比向垂直方向绕路快,所以,我们不妨以折线的方式移动,直到横坐标或纵坐标等于终点时,向同一方向间隔移动。

时间复杂度:\(O(1)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f, mod = 998244353;

void init(){}

void solve() {
    int a, b;
    cin >> a >> b;
    a = abs(a), b = abs(b);
    cout << (a + b) + (a != b ? abs(a - b) - 1 : 0) << '\n';
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    init();
    int t;
    cin >> t;
    while (t --) solve();
}

画个图的事情((

B. Vaccination

题意

对于 \(n\) 个病人,每个病人需要在 \([t_i, t_i + w]\) 时间内被扎一针。在某个时间点 \(x\),可以拿出一个包含 \(k\) 个剂量的包装,这个包装会在 \(x + d + 1\) 时过期。给定整数 \(n, k, d, w\),输出需要拿出的包装的最小数量。

思路

为了要当前的包装可以包括更多的人,我们不妨在某一个病人的 \(t_i + w\) 时刻拿出包装,并枚举后面有多少个 \(t_j\) 小于 \(t_i + w + d\),这样即可贪心地求出最小值。

就这样,没了。

时间复杂度:\(O(n)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f, mod = 998244353;

void init(){}

void solve() {
    int n, k, d, w;
    cin >> n >> k >> d >> w;
    int ans = 0;
    vector<pii> a(n);
    for(int i=0;i<n;i++){
        cin >> a[i].first;
        a[i].second = a[i].first + w;
    }
    int i = 0;
    while(i < n){
        int l = a[i].second, r = l + d;
        int now = i;
        for(int j=0;j<k;j++){
            if(i + j >= n || a[i + j].first > r) break;
            now ++;
        }
        ans ++;
        i = now;
    }
    cout << ans << '\n';
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    init();
    int t;
    cin >> t;
    while (t --) solve();
}

这还需要证明吗,这还需要证明吗(

C. Pull Your Luck

题意

给定一个圆盘,按顺序写好了 \(0, 1, 2, ..., n - 1\),换言之,\(0, n - 1\) 相邻。规定可以转动 \(p\) 秒,第一秒将当前值增加 \(p\),第二次增加 \(p - 1\),以此类推。对于给定的起点,输出是否可以进行一次 \([1, p]\) 秒的转动,使终点为 \(0\)

思路

首先,我们很容易列出一个式子:

\(n - x + kn = \frac{p(p+1)}{2}\)  

但这个式子推不了什么。

有趣的是,若我们一直循环加上数的话,在取到 \(n-1\) 之后,所有数均会变小,但值得注意的是这些数因均相邻而出现了周期。

因而,在一个周期内,若出现了 \(0\),输出即可。能保证最后的复杂度足够小。

时间复杂度:不大就对了

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f, mod = 998244353;

void init(){}

void solve() {
    int n, x, p;
    cin >> n >> x >> p;
    int cur = x;
    for(int i=1;i<=min(p, 2*n);i++){
        cur = (cur + i) % n;
        if(cur == 0) {
            cout << "YES\n";
            return;
        }
    }
    cout << "NO\n";
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    init();
    int t;
    cin >> t;
    while (t --) solve();
}

捏吗,一直在想怎么搞式子

D. Accommodation

题意

给定 \(n\) 个长度为 \(m\) 的二进制串,满足 \(m \bmod 4 = 0\),将字符串分割为 \(\frac{m}{4}\) 个长度为 \(2\) 的子串和 \(\frac{m}{2}\) 个长度为 \(1\) 的子串。输出所有含 \(1\) 子串个数总和的最大值和最小值。

思路

若我们需要让个数尽可能大,我们当然希望将 \(11\) 分割开,也就是构造非 \(11\) 的大窗,那么,我们不妨枚举所有含有 \(0\) 的可能的大窗,拿掉这些后,剩余的作为小窗,即可让个数尽可能大。

相反地,要让个数尽可能小,我们就希望尽可能不将 \(11\) 分割开,也就是主动构造为 \(11\) 的大窗,这时,能构造多少个,\(1\) 的个数就能减少多少。

有趣的是,只要分割出 \(\frac{m}{4}\) 个长度为 \(2\) 的子串,剩余的一定长度均为 \(1\),且恰好 \(\frac{m}{2}\) 个;反之亦然。

当然,如果这题数据量小的话,可以 \(dp\)

时间复杂度:\(O(nm)\)

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f, mod = 998244353;

void init(){}

void solve() {
    int n, m;
    cin >> n >> m;
    int mn = 0, mx = 0;
    while (n--) {
        string s;
        cin >> s;
        int c1 = 0, c2 = 0, tot = 0;
        for (int i = 0; i < m; i++) tot += s[i] - '0';
        for (int i = 0; i < m - 1; i ++)
            if (s[i] == '1' && s[i + 1] == '1') c1 ++, i ++;
        for (int i = 0; i < m - 1; i ++)
            if (s[i] == '0' || s[i + 1] == '0') c2 ++, i ++;
        mn += tot - min(c1, m / 4);
        mx += tot - max(0ll, m / 4 - c2);
    }
    cout << mn << ' ' << mx << '\n';
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    init();
    int t = 1;
    //cin >> t;
    while (t --) solve();
}

似了,在想怎么dp,贪心还没贪对(一直想着拆