“葡萄城杯”牛客周赛 Round 53

小红小紫投硬币

思路:签到题,直接猜 0.5 0.5 0.5

void solve() {
    int n; cin >> n;
    cout << 0.50000000 << '\n';
}

小红的字符串

思路:就看看左右两端变成左边的字符还是右边的字符花费的代价更小就用哪边

void solve() {
    string s; cin >> s;
    int l = 0, r = s.size() - 1;
    int ans = 0;
    while (l < r) {
        char o1 = s[l], o2 = s[r];
        if (o1 > o2) {
            swap(o1, o2);
        }
        int c1 = o2 - o1;
        int c2 = 'z' - o2 + o1 - 'a' + 1;
        ans += min(c1, c2);
    }
    cout << ans << '\n';
}

小红的 01 消除

思路:就是用 1 1 1去抵消 0 0 0

void solve() {
    int n; cin >> n;
    string s; cin >> s;
    int x, y, z; cin >> x >> y >> z;
    int c0 = 0;
    bool ok = false;
    int ans = 0;
    for (auto c : s) {
        if (!y) break;
        if (c == '0') c0++;
        else if (c0) ans++, c0--, y --;
    }
    cout << ans << '\n';
}

小红组比赛

思路:一眼 d p dp dp d p [ i ] [ j ] dp[i][j] dp[i][j]表示选前 i i i场比赛的某一个题所能得到 j j j的分数, d p [ i ] [ j ] = 0 dp[i][j] = 0 dp[i][j]=0表示不行, d p [ i ] [ j ] = 1 dp[i][j] = 1 dp[i][j]=1 表示行,最后所有可能的分数和目标值的差值更新答案就行

void solve() {
    int n, m; cin >> n >> m;
    vector<vector<int>> t(n + 1);
    int ans = INF;
    for (int i = 1; i <= n; i ++) {
        for (int j = 1, x; j <= m; j ++) {
            cin >> x;
            t[i].push_back(x);
        }
    }
    vector<vector<int>> dp(n + 1, vector<int>(5010));
    dp[0][0] = 1;
    int target; cin >> target;
    for (int i = 1; i <= n; i ++) {
        for (auto j : t[i]) {
            for (int k = j; k <= 5010; k ++) {
                dp[i][k] |= dp[i - 1][k - j];
            }
        }
    }
    for (int i = 0; i < 5010; i ++) {
        if (dp[n][i]) ans = min(ans, abs(target - i));
    }
    cout << ans << '\n';
}

折半丢弃

思路:二分 m e x mex mex,因为 m e x mex mex越小越容易满足,越大可能不容易满足,具有二分性,先把 a [ i ] a[i] a[i]通过除 2 2 2可以变为那些数存下来, v e [ i ] ve[i] ve[i]表示哪些数可以通过除 2 2 2变为 i i i,然后二分每次 c h e c k check check的时候从 m i d mid mid往前判断是否可以,因为 m e x mex mex越大满足的数越少, m e x mex mex越小可能的数越多

void solve() {
    int n; cin >> n;
    vector<int> a(n + 1);
    map<int, int> mp;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        mp[a[i]] ++;
    }
    vector<vector<int>> ve(n + 1);
    for (int i = 1; i <= n; i ++) {
        int x = a[i];
        while (x) {
            if (x >= n) {
                x >>= 1;
                continue;
            }
            ve[x].push_back(a[i]);
            x >>= 1;
        }
        ve[0].push_back(a[i]);
    }
    auto check = [&](int x) -> bool {
        auto vis = mp;
        for (int i = x; i >= 0; i --) {
            bool ok = false;
            for (auto j : ve[i]) {
                if (vis[j]) {
                    vis[j] --;
                    ok = true;
                    break;
                }
            }
            if (!ok) return false;
        }
        return true;
    };
    int l = 0, r = n, ans = -1;
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid)) l = mid + 1, ans = mid;
        else r = mid - 1;
    }
    cout << ans + 1 << '\n';
}

小红走矩阵

思路:其实感觉这个很像分层图,并且我们想一下,他只有可能不走左边或上边,所以就只有三种情况,正常走,不走左边,不走上边,可以写三个 b f s bfs bfs来处理,我为了方便直接在一个 b f s bfs bfs函数里面进行, v i s [ i ] [ j ] [ k ] [ l ] vis[i][j][k][l] vis[i][j][k][l]表示 i i i j j j这个位置不能往 k k k这种类型的方向走 l l l 0 0 0表示不能穿墙, 1 1 1表示可以,然后就是队列里面维护位置,不能走那个方向,能否穿墙,距离起点的距离

int n, m, ans;
char g[N][N];
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};
int vis[N][N][5][2];

int bfs() {
    queue<array<int, 5>> q;
    q.push({1, 1, 2, 1, 0});
    q.push({1, 1, 3, 1, 0});
    q.push({1, 1, 4, 0, 0});
    vis[1][1][2][1] = 1;
    vis[1][1][3][1] = 1;
    vis[1][1][4][0] = 1;
    while (q.size()) {
        auto t = q.front();
        q.pop();
        for (int i = 0; i < 4; i ++) {
            if (i == t[2]) continue;
            int tx = t[0] + dx[i];
            int ty = t[1] + dy[i];
            if (tx < 1 || ty < 1 || tx > n || ty > m) continue;
            if (vis[tx][ty][t[2]][t[3]]) continue;
            if (tx == n && ty == m) return t[4] + 1;
            if (g[tx][ty] == 'X') {
                if (t[3]) {
                    vis[tx][ty][t[2]][t[3]] = 1;
                    q.push({tx, ty, t[2], 0, t[4] + 1});
                }
            } else {
                vis[tx][ty][t[2]][t[3]] = 1;
                q.push({tx, ty, t[2], t[3], t[4] + 1});
            }
        }
    }
    return -1;
}

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            cin >> g[i][j];
        }
    }
    ans = bfs();
    cout << ans << '\n';
}

游游的删点直径

思路:待补

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值