2022 CCPC 女生赛

A. 减肥计划

因为当\(k\ge n\)时,最大值一定是答案。并且队头的值是不会减少的。所以从对头出队又从队尾入队的一定不是答案。所以最多进行\(n\)次,用双端队列模拟一下即可。

#include <bits/stdc++.h>

using namespace std;


int32_t main() {
    int n , k , maxVal = 0, res = 0;
    scanf("%d%d" , &n,&k);
    deque<pair<int, int> > q;
    for (int i = 1, x; i <= n; i++)
         scanf("%d" , &x ) , maxVal = max(maxVal, x), q.emplace_back(x, i);
    int cnt = 0, cntID = 0;
    for (int i = 1 , aVal , aID , bVal , bID; i <= n; i++) {
        aVal = q.front().first , aID = q.front().second , q.pop_front();
        bVal = q.front().first , bID = q.front().second , q.pop_front();
        if (aVal == maxVal) {
            res = aID;
            break;
        }
        if (aVal >= bVal) {
            if (cntID == aID) cnt++;
            else cntID = aID, cnt = 1;
            if (cnt >= k) {
                res = aID;
                break;
            }
            q.emplace_front(aVal, aID), q.emplace_back(bVal, bID);
        } else {
            cntID = bID, cnt = 1;
            if (cnt >= k) {
                res = bID;
                break;
            }
            q.emplace_back( aVal , aID ) , q.emplace_front( bVal , bID );
        }
    }
    printf("%d\n", res);
    return 0;
}

C. 测量学

因为两个方向都可以走所以首先要\(\theta = \min(\theta,2\pi-\theta)\),大圆走小圆绕的距离是\(2(R-r)+\theta r\),也可以直接走大圆就是\(\theta R\),枚举取最小值即可

#include <bits/stdc++.h>

using namespace std;

int32_t main() {
    long double n , r , p , res , pi=3.14159265358979323846;
    cin >> n >> r >> p;
    p = min( p , 2.0 * pi - p );
    res = r * p;
    for( int i = 1 ; i < n ; i ++ ){
        long double x; cin >> x;
        res = min( res , 2 * ( r - x ) + x * p );
    }
    cout << fixed << setprecision(6) << res;
    return 0;
}

E. 睡觉

因为可以循环做,所以我采用了一个技巧破环成链,直接把a数组存两边。

然后如果两边可以直接睡着的,就可以直接结束。然后我们考虑需要重复很多遍的情况。

如果完整的播完一遍之后,清醒度比一开始要低的,则一定可以睡着。如果播完一遍后,清醒度比一开始要高,则一定无法入睡。如果保持不变,此时则要判断过程中清醒度时候一直小于等k如果小于,足够的时间后也可以入睡

#include <bits/stdc++.h>

using namespace std;

#define int long long

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

void solve() {
    int x = read(), t = read(), k = read(), n = read(), d = read();
    vector<int> a(2 * n + 5), f(2 * n + 5);
    for (int i = 1; i <= n; i++) a[i] = a[i + n] = read();
    f[0] = x;
    for (int i = 1 , cnt = 0 ; i <= n * 2; i++) {
        if (a[i] <= d) f[i] = max(f[i - 1] - 1, 0ll);
        else f[i] = f[i - 1] + 1;
        if( f[i] <= k ) cnt ++;
        else cnt = 0;
        if( cnt >= t ){
            printf("YES\n");
            return;
        }
    }
    if( f[n] < f[0] ){
        printf("YES\n");
        return;
    }else if( f[n] == f[0] && f[0] == k && t >= n ){
        bool flag = true;
        for( int i = 1 ; flag && i <= n ; i ++ )
            if( f[i] > k ) flag = false;
        if(flag) printf("YES\n");
        else printf("NO\n");
    }else printf("NO\n");
    return;
}

int32_t main() {
    for (int t = read(); t; t--) solve();
    return 0;
}

G. 排队打卡

这道题的做法就是模拟这个过程就好,但是要注意一个细节排队是在这一秒开始的时候进行,但进入入口是在这一秒结束的时候进行。

在模拟的过程中验证n时候正确并且枚举排队的时间,计算一下进入的时间就好

#include <bits/stdc++.h>

using namespace std;

#define int long long

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int32_t main() {
    int t = read(), n = read(), m = read(), k = read(), res, val = LLONG_MAX;
    vector<pair<int, int>> p(m);
    for (auto &[ti, xi]: p) ti = read(), xi = read();
    p.emplace_back(t, 0);
    sort(p.begin(), p.end());
    int last = 0, preTime = p.front().first - 1;
    for (auto [ti, xi]: p) {
        // ti 秒初
        last = max(0ll, last - k * (ti - preTime - 1));
        if (ti == t) {
            if (last != n) cout << "Wrong Record\n", exit(0);
            continue;
        }
        last += xi;
        if (ti > t) {
            int ans = (last + k) / k;
            if (ans <= val) val = ans, res = ti;
        }
        // ti 秒末
        preTime = ti, last = max(0ll, last - k);
    }
    cout << res << " " << val << '\n';
    return 0;
}

H. 提瓦特之旅

如果没有委托这个条件的话,这就是一个最短路的题目了。我们还要解决的问题是委托,委托其实和访问哪些点无关,之和访问点的个数有关。并且这里点数只有500。我们可以在计算最短路的过程中记录f[i][j]表示到达点i经过j个点的最短路。这样直接用bfs计算f[i][j],然后\(O(n)\)的回答就好,复杂度\(O(nq)\)

#include <bits/stdc++.h>

using namespace std;

#define int long long

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

typedef pair<int, int> PII;

const int inf = 1e17;

int32_t main() {
    int n = read(), m = read();
    vector<vector<PII>> e(n + 1);
    vector<vector<int>> f(n + 1, vector<int>(n + 1, inf ) );
    for (int u, v, w; m; m--)
        u = read(), v = read(), w = read(), e[u].emplace_back(v, w), e[v].emplace_back(u, w);
    f[1][0] = 0;
    queue<pair<int, int> > q;
    q.emplace(1, 0);
    while (!q.empty()) {
        auto [u, step] = q.front();
        q.pop();
        if( step == n-1 ) continue;
        for (auto [v, w]: e[u]) {
            if (f[v][step + 1] <= f[u][step] + w) continue;
            f[v][step + 1] = f[u][step] + w;
            q.emplace( v , step + 1 );
        }
    }

    for( int i = 1 ; i <= n ; i ++ )
        for( int j = 1 ; j < n ; j ++ )
            f[i][j] = min( f[i][j] , f[i][j-1] );


    for( int q = read() , t , res ; q ; q -- ){
        vector<int> w(n);
        for( auto & i : w ) i = read();
        t = w[0] , res = LLONG_MAX ;
        for( int i = 1 , sum = 0 ; i < n ; i ++ ){
            sum += w[i];
            if( f[t][i] == inf ) continue;
            res = min( res , f[t][i] + sum );
        }
        printf("%lld\n" , res );
    }
    return 0;
}

I. 宠物对战

f[i][0/1]表示前i位,且最后一位是a/b是否成立

然后我们枚举当前这一个字符串的长度,然后去查询这个字符串是否再对应的集合中存在即可。查询,我使用了Trie树实现。

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 5;
int sonB[N][26], cntB[N], idxB;
int sonA[N][26], cntA[N], idxA;

void insert(string s, int son[][26], int cnt[], int &idx) {
    int p = 0;
    for (int i = 0; i < s.size(); i++) {
        int u = s[i] - 'a';
        if (!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
    cnt[p]++;
}

int query(string s, int son[][26], int cnt[], int &idx) {
    int p = 0;
    for (int i = 0; i < s.size(); i++) {
        int u = s[i] - 'a';
        if (!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}

int f[N][2];

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    string s;
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> s, insert(s, sonA, cntA, idxA);

    cin >> n;
    for (int i = 1; i <= n; i++) cin >> s, insert(s, sonB, cntB, idxB);

    cin >> s;
    n = s.size() , s = " "+s;
    vector<array<int, 2> > f(n + 1);

    for (int i = 1; i <= n; i++) f[i][0] = f[i][1] = INT_MAX;

    for (int i = 0; i <= n; i++) {
        if (f[i][1] < INT_MAX) {
            int p = 0;
            for (int j = i + 1 , u ; j <= n ; j ++ ){
                u = s[j] - 'a';
                if( sonA[p][u] == 0 ) break;
                p = sonA[p][u];
                if( cntA[p] ) f[j][0] = min( f[j][0] , f[i][1] +1 );
            }
        }
        if( f[i][0] < INT_MAX ){
            int p = 0;
            for( int j = i + 1 , u ; j <= n ; j ++ ){
                u = s[j] - 'a';
                if( sonB[p][u] == 0 ) break;
                p = sonB[p][u];
                if( cntB[p] ) f[j][1] = min( f[j][1] , f[i][0] + 1 );
            }
        }
    }
    int res = min(f[n][1], f[n][0]);
    if (res == INT_MAX) res = -1;
    cout << res;
}
posted @ 2023-02-11 17:10  PHarr  阅读(180)  评论(0编辑  收藏  举报