• “蔚来杯“2022牛客暑期多校训练营6 ABM题解


    A-Array

    题目大意:
    给出一个序列a1、a2 … an ,a的倒数和小于等于1/2,构造一个序列(首位相连),使得相邻的i之间不超过ai

    思路:
    只要a的倒数和小于1,就可以保证这个序列的存在的。因此将每个a取小于a的最大的2的次幂,可以保证改变后的a的倒数和小于1,然后将a排序,从小到达往序列中放数即可,当放置的位置有数字时就向后移动到空位置,因此都是2的次幂,因此一旦找到空位置后,之后每隔ai的位置都是空的,这也是将a取成2的次幂的原因。可以说这是一道非常巧妙的题。

    AC代码:

    #include 
    #define mem(a, v) memset(a, v, sizeof(a))
    using namespace std;
    
    const long long mod = 1e9 + 7;
    
    long long ksm(long long base, long long power)
    {
        long long result = 1;
        base %= mod;
        while (power)
        {
            if (power & 1)
                result = (result * base) % mod;
            power >>= 1;
            base = (base * base) % mod;
        }
        return result;
    }
    
    long long dp[14][150];
    
    long long dfs(int s, int r)
    {
        if (dp[s][r] != 0) return dp[s][r];
        if (s == r)
            dp[s][r] = (s + 1) / 2;
        else if (s == 1)
            dp[1][r] = (1 + (r - 3) * ksm(r, mod - 2) % mod * dfs(s, r - 1) % mod) % mod;
        else
            dp[s][r] = (1 + 3 * s * ksm(r, mod - 2) % mod * dfs(s - 2, r - 1) % mod + (r - 3 * s) * ksm(r, mod - 2) % mod * dfs(s, r - 1) % mod) % mod;
        return dp[s][r];
    }
    
    signed main()
    {
        mem(dp, 0);
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        int t, cnt;
        char str[50];
        map<int, int> m;
        cin >> t;
        for (int i = 1; i <= t; i++)
        {
            m.clear();
            cnt = 0;
            cin >> str;
            for (int j = 0; j < 26; j += 2)
                m[str[j] * 137 + str[j + 1]]++;
            for (auto it : m)
                if (it.second == 1) cnt++;
            cout << "Case #" << i << ": " << dfs(cnt, 123) << "\n";
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    B-Eezie and Pie

    题目大意:
    有一棵树,每个结点向上能达到的距离为di , 对于每个点,求出能到达该点的点数。

    思路:
    类似前缀和的做法,初始时每个点的值为1,得到每个点不能到达的最近祖先,将其值减1。从下往上算出每个点的值,计算方法为该点自身的值加上所有子树的值。
    找最大祖先如果用倍增的话,复杂度为O(nlogn),可能会被卡常数,另一种方法是在dfs时用一个数组来记录路径上的点,从而用O(n)的方法找到每个点的最大祖先。

    AC代码:

    #include 
    const int N = 2e6 + 5;
    using namespace std;
    
    vector<int> g[N];
    int path[N], d[N], ans[N], n, cnt = 0;
    
    void dfs(int u, int f)
    {
        path[++cnt] = u;    //将当前的点加入路径中
        if (d[u] + 1 < cnt) //不能到达的最近祖先减1
            ans[path[cnt - d[u] - 1]]--;
        for (auto v : g[u])
        {
            if (v == f) continue;
            dfs(v, u);
        }
        for (auto v : g[u])
        {
            if (v == f) continue;
            ans[u] += ans[v];
        }
        cnt--; // dfs结束,将该点弹出
    }
    
    signed main()
    {
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        int u, v;
        cin >> n;
        for (int i = 1; i <= n; i++)
            ans[i] = 1;
        for (int i = 2; i <= n; i++)
        {
            cin >> u >> v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        for (int i = 1; i <= n; i++)
            cin >> d[i];
        dfs(1, 0);
        for (int i = 1; i <= n; i++)
            cout << ans[i] << ' ';
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    M-Z-Game on grid

    题目大意:
    在一个矩形棋盘上,每个位置可能为’A’、‘B’、'.‘其中之一,Alice和Bob轮流移动棋子,每次只能向右或向下移动棋子,当棋子移动到’A’上时Alice获胜,当棋子移动到’B’上时Bob获胜,当棋子不能被移动且位于’.'上时,平局。棋子初始位置在左上角,Alice先手,Bob走的每一步都是随机的,问Alice能否控制自己获胜、平局或是输掉。

    思路:
    可以把两人移动棋子的情况画成一棵树,以Alice获胜为例,那么无论Bob怎么走,棋子总是位于获胜的路径上。
    当Alice移动时,子树中至少要有一棵位于获胜的路径上才行,当Bob移动时,所有的子树都必须位于获胜的路径上。

    AC代码:

    #include 
    #define mem(a, v) memset(a, v, sizeof(a))
    const int N = 5e2 + 5;
    using namespace std;
    
    char g[N][N];
    int n, m;
    int sg[2][N][N]; // sg[0][i][j]表示棋子位于(i,j)上且是Alice移动的结果
    
    // Alice赢,p为0表示为Alice在走,1表示Bob走
    bool dfs1(int p, int i, int j)
    {
        if (sg[p][i][j] != -1) return sg[p][i][j]; //已经有结果了,直接返回
        if (g[i][j] == 'A') return 1;   //赢了
        if (g[i][j] == 'B') return 0;   //输了
        if (i == n && j == m) return 0; //平局
        bool res;
        if (p == 0) // Alice走,有一条路径为获胜路径就行
        {
            res = 0;
            if (i + 1 <= n) res |= dfs1(p ^ 1, i + 1, j);
            if (j + 1 <= m) res |= dfs1(p ^ 1, i, j + 1);
            sg[p][i][j] = res;
        }
        else // Bob走,所有的路径为获胜路径才行
        {
            res = 1;
            if (i + 1 <= n) res &= dfs1(p ^ 1, i + 1, j);
            if (j + 1 <= m) res &= dfs1(p ^ 1, i, j + 1);
            sg[p][i][j] = res;
        }
        return sg[p][i][j];
    }
    
    //平局
    bool dfs2(int p, int i, int j)
    {
        if (sg[p][i][j] != -1) return sg[p][i][j];
        if (g[i][j] != '.')
            return 0;
        if (i == n && j == m && g[i][j] == '.') return 1;
        bool res;
        if (p == 0)
        {
            res = 0;
            if (i + 1 <= n) res |= dfs2(p ^ 1, i + 1, j);
            if (j + 1 <= m) res |= dfs2(p ^ 1, i, j + 1);
            sg[p][i][j] = res;
        }
        else
        {
            res = 1;
            if (i + 1 <= n) res &= dfs2(p ^ 1, i + 1, j);
            if (j + 1 <= m) res &= dfs2(p ^ 1, i, j + 1);
            sg[p][i][j] = res;
        }
        return sg[p][i][j];
    }
    // Bob赢
    bool dfs3(int p, int i, int j)
    {
        if (sg[p][i][j] != -1) return sg[p][i][j];
        if (g[i][j] == 'B') return 1;
        if (g[i][j] == 'A') return 0;
        if (i == n && j == m) return 0;
        bool res;
        if (p == 0) // A走
        {
            res = 0;
            if (i + 1 <= n) res |= dfs3(p ^ 1, i + 1, j);
            if (j + 1 <= m) res |= dfs3(p ^ 1, i, j + 1);
            sg[p][i][j] = res;
        }
        else
        {
            res = 1;
            if (i + 1 <= n) res &= dfs3(p ^ 1, i + 1, j);
            if (j + 1 <= m) res &= dfs3(p ^ 1, i, j + 1);
            sg[p][i][j] = res;
        }
        return sg[p][i][j];
    }
    
    void solve()
    {
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
            cin >> g[i] + 1;
    
        mem(sg, -1);
        if (dfs1(0, 1, 1))
            cout << "yes ";
        else
            cout << "no ";
    
        mem(sg, -1);
        if (dfs2(0, 1, 1))
            cout << "yes ";
        else
            cout << "no ";
    
        mem(sg, -1);
        if (dfs3(0, 1, 1))
            cout << "yes\n";
        else
            cout << "no\n";
    }
    
    signed main()
    {
        ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        int T;
        cin >> T;
        while (T--)
            solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
  • 相关阅读:
    ctfshow XSS
    股票交易接口的分类webService接口
    【深度学习】实验 — 动手实现 GPT【三】:LLM架构、LayerNorm、GELU激活函数
    Python零基础速成班-第16讲-Python for Matplotlib 线图、散点图、柱形图、饼图
    JUC并发编程笔记2
    TCP编程
    Golang Redis连接池封装
    SpringBoot+Mybatis+定时任务实现大数据量数据分表记录和查询
    软考网络工程师路由器配置考点总结
    AC修炼计划(AtCoder Regular Contest 165)
  • 原文地址:https://blog.csdn.net/Shanhj/article/details/126279224