【MX-J15】梦熊J组·儿童节赛 题解

【MX-J15】梦熊J组·儿童节赛 题解

T1 叉叉学习数据类型

学习语法阶段的时候说过,超过对应数据范围的数就会溢出,我们利用这个特性就可以写:

#include <bits/stdc++.h>
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MOD = 998244353;
const int N = 1e6 + 10;

void solve() {
    string s; cin >> s;
    int c1 = 0;
    unsigned int c2 = 0;
    long long c3 = 0;
    unsigned long long c4 = 0;
    int n = s.size();
    if (s[0] == '-') {
        bool flag1, flag2, flag3, flag4;
        flag1 = flag3 = true;
        flag2 = flag4 = false;
        for (int i = 1; i < n; i ++ ) {
            int now1 = c1 * 10 - (s[i] - '0');
            long long now3 = c3 * 10 - (s[i] - '0');
            if (now1 > c1) flag1 = false;
            if (now3 > c3) flag3 = false;
            c1 = now1, c3 = now3;
        }
        if (flag1) cout << "int\n";
        if (flag3) cout << "long long\n";
        cout << "string\n";
    } else {
        bool flag1, flag2, flag3, flag4;
        flag1 = flag2 = flag3 = flag4 = true;
        for (int i = 0; i < n; i ++ ) {
            int now1 = c1 * 10 + s[i] - '0';
            unsigned int now2 = c2 * 10 + s[i] - '0';
            long long now3 = c3 * 10 + s[i] - '0';
            unsigned long long now4 = c4 * 10 + s[i] - '0';
            if (now1 < c1) flag1 = false;
            if (now2 < c2) flag2 = false;
            if (now3 < c3) flag3 = false;
            if (now4 < c4) flag4 = false;
            c1 = now1, c2 = now2, c3 = now3, c4 = now4;
        }
        if (flag1) cout << "int\n";
        if (flag2) cout << "unsigned int\n";
        if (flag3) cout << "long long\n";
        if (flag4) cout << "unsigned long long\n";
        cout << "string\n";
    }
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int T = 1;
    // cin >> T;
    while (T -- ) solve();
    return 0;
}

T2 叉叉学习位运算

读题后了解到,头尾的0可以随便添,但是1不可以,所以我们考虑把 \(b\) 的最低连续0给去掉,然后看看该串在 \(a\) 中是否出现过即可

#include <bits/stdc++.h>
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef unsigned long long ULL;
const int INF = 0x3f3f3f3f;
const int MOD = 998244353;
const int N = 1e6 + 10;

string ULL2String(ULL x) {
    string ans = "";
    while (x) {
        ans.push_back(char('0' + (x & 1)));
        x >>= 1;
    }
    if (ans == "") ans = "0";
    reverse(ans.begin(), ans.end());
    return ans;
}

void solve() {
    ULL a, b; cin >> a >> b;
    if (b == 0) {
        cout << "Yes\n";
        return ;
    }
    string ta = ULL2String(a);
    string tb = ULL2String(b);
    // cout << ta << ' ' << tb << endl;
    while (tb.size() > 1 && tb.back() == '0') tb.pop_back();
    for (int i = 0; i < ta.size(); i ++ ) {
        string t = ta.substr(i, tb.size());
        if (t == tb) {
            cout << "Yes\n";
            return ;
        }
    }
    cout << "No\n";
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int T = 1;
    cin >> T;
    while (T -- ) solve();
    return 0;
}

T3 叉叉学习与自我和解

模拟一下样例,我们发现一个问题:多连的线只要保证不会出现新的最短路就行了。

我们将给定的树的根记作 \(0\) ,那么众所周知,对于一棵树来说,任何一个点到树根的最短路就是深度。所以我们思考一个问题:如何连边会出现更短的路。

很明显,例如1点在第5层,那么当它往第4层连边都是没事的,但是往第3层,第2层连边就不行了。可以自己多举一些例子来帮助理解。

所以我们发现,对于每个点来说,可以连的边的个数就是同层的点数,以及下面和上面那一层的点数,当然要减去自己和已经连接的点。

然后我们的策略就是,这些边可以选也可以不选,设有 \(m\) 条边可以连,那么答案就是 \(2^m\) ,边数很多,需要用快速幂

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int N = 1e6 + 10;

vector<int> g[N];
int c[N];
int f[N];

void dfs(int u, int last, int dep) {
    f[u] = dep;
    c[dep] ++;
    for (int v : g[u]) {
        if (v == last) continue;
        dfs(v, u, dep + 1);
    }
}
LL q_pow(LL a, LL b) {
    LL ans = 1;
    while (b) {
        if (b & 1) ans = ans * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ans;
}

void solve() {
    int n; cin >> n;
    for (int i = 1; i < n; i ++ ) {
        int u, v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(0, -1, 1);
    LL ans = 0;
    for (int i = 1; i < n; i ++ ) {
        int now = f[i];
        ans += c[now] - 1;
        if (c[now + 1]) ans += c[now + 1] - (g[i].size() - 1);
        if (c[now - 1]) ans += c[now - 1] - 1;
    }
    ans /= 2;
    cout << q_pow(2, ans) << endl;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int T = 1;
    // cin >> T;
    while (T -- ) solve();
    return 0;
}

T4 叉叉学习魔法

题目要求求出在步数最小的前提下,使用魔法次数最少。

那我们先求出最小步数,然后在最短路转移的时候求出最少魔法次数即可。

由于边权只有0和1,所以可以使用双端队列BFS。

但是这道题会卡deque,所以需要手写deque

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<int, pair<int, int>> PIII;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int N = 5050 + 10;

char g[N][N];
int dis[N][N], f[N][N];
bool vis[N][N];
PII q[N * N * 2];
int he, ta;
int dx[] = {1, -1, 0, 0, 1, 1, -1, -1};
int dy[] = {0, 0, 1, -1, 1, -1, 1, -1};

void solve() {
    int n, m; cin >> n >> m;
    int stx, sty, edx, edy;
    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) {
            cin >> g[i][j];
            if (g[i][j] == 'X') {
                stx = i, sty = j;
            } else if (g[i][j] == 'W') {
                edx = i, edy = j;
            }
        }
    }
    he = N * N + 1, ta = N * N;
    memset(dis, 0x3f, sizeof dis);
    memset(f, 0x3f, sizeof f);
    q[++ ta] = {stx, sty};
    dis[stx][sty] = f[stx][sty] = 0;
    while (he <= ta) {
        PII t = q[he]; he ++;
        int nx = t.first, ny = t.second;
        vis[nx][ny] = true;
        // cout << nx << ' ' << ny << ' ' << dis[nx][ny] << ' ' << f[nx][ny] << endl;
        for (int i = 0; i < 8; i ++ ) {
            int x = nx + dx[i], y = ny + dy[i];
            if (vis[x][y]) continue;
            if (x < 1 || x > n || y < 1 || y > m) continue;
            if (g[x][y] == '#') continue;
            if (dis[x][y] > dis[nx][ny] + (i < 4)) {
                dis[x][y] = dis[nx][ny] + (i < 4);
                if (i < 4) q[++ ta] = {x, y};
                else q[-- he] = {x, y};
            }
        }
    }
    if (!vis[edx][edy]) {
        cout << -1 << ' ' << -1 << endl;
        return ;
    }
    memset(vis, 0, sizeof vis);
    he = N * N + 1, ta = N * N;
    q[++ ta] = {stx, sty};
    while (he <= ta) {
        PII t = q[he]; he ++;
        int nx = t.first, ny = t.second;
        if (vis[nx][ny]) continue;
        for (int i = 0; i < 8; i ++ ) {
            int x = nx + dx[i], y = ny + dy[i];
            if (vis[x][y]) continue;
            if (x < 1 || x > n || y < 1 || y > m) continue;
            if (g[x][y] == '#') continue;
            if (dis[x][y] == dis[nx][ny] + (i < 4)) {
                if (f[x][y] > f[nx][ny] + (i >= 4)) {
                    f[x][y] = f[nx][ny] + (i >= 4);
                    if (i >= 4) q[++ ta] = {x, y};
                    else q[-- he] = {x, y};
                }
            }
        }
    }
    cout << dis[edx][edy] << ' ' << f[edx][edy] << endl;
}
int main() {
    ios::sync_with_stdio(false), cin.tie(0);
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int T = 1;
    // cin >> T;
    while (T -- ) solve();
    return 0;
}
posted @ 2025-06-02 00:07  Time_Limit_Exceeded  阅读(65)  评论(0)    收藏  举报