• AtCoder Beginner Contest 226


    A - Round decimals

    将给定的浮点数四舍五入。

    \(round(x)\)

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
     
    int main()
    {
        double n;
        cin >> n;
        cout << round(n) << "\n";
        return 0;
    }
    

    B - Counting Arrays

    \(n\) 个序列,求不同的序列个数?

    \(set\) 去重

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
     
    int n;
    set<vector<int> > S;
     
    int main()
    {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n;
        while(n -- )
        {
            int k, x;
            vector<int> v;
            cin >> k;
            while(k -- )
            {
                cin >> x;
                v.push_back(x);
            }
            S.insert(v);
        }
        cout << (int)S.size() << "\n";
        return 0;
    }
    

    C - Martial artist

    \(n\) 个动作需要学,学习动作 \(i\) 需要时间 \(T_i\), 只有学完一个动作才能学另一个,动作之间有依赖关系,求学会动作 \(n\) 所需的最少时间?

    建图,能够走到动作 \(n\) 的所有动作都需要学,不妨把 \(n\) 当作起点,遍历所有能到达的点。

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
     
    typedef long long LL;
    const int N = 2e5 + 20;
     
    int n, w[N];
    vector<int> G[N];
    bool st[N];
    LL ans;
     
    void DFS(int u)
    {
        st[u] = true;
        ans += w[u];
        for(auto v : G[u])
            if(!st[v])
                DFS(v);
    }
     
    int main()
    {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n;
        for(int i = 1; i <= n; ++ i)
        {
            cin >> w[i];
            int k, x; 
            cin >> k;
            while(k -- )
            {
                cin >> x;
                G[i].push_back(x);
            }
        }
        DFS(n);
        cout << ans << "\n";
        return 0;
    }
    

    D - Teleportation

    二维坐标系上有 \(n\) 个点,可以使用一种操作 \((a, b)\) , 从 \((x, y)\) 移动到 \((x + a, y + b)\)

    若想在任意两个点之间互相到达,所需的最少操作种类数?

    \(g = gcd(a, b)\), \((a, b)\) 一定可以由 \((\dfrac{a}{g}, \dfrac{b}{g})\) 凑出。

    统计任意两点 \(i\)\(j\) 间距离 \((x_i - x_j, y_i - y_j)\), 令 \(g_{i, j} = gcd(|x_i - x_j|, |y_i - y_j|)\)

    答案即为 \((\dfrac{x_i - x_j}{g_{i,j}}, \dfrac{y_i - y_j}{g_{i,j}})\) 的不同种类数。

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
     
    const int N = 500 + 10;
     
    int n;
    int x[N], y[N];
    set<pair<int, int> > S;
     
    int main()
    {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);    
        cin >> n;
        for(int i = 1; i <= n; ++ i)
            cin >> x[i] >> y[i];
        for(int i = 1; i <= n; ++ i)
            for(int j = 1; j <= n; ++ j)
            {
                if(i == j) continue;
                int xx = x[i] - x[j], yy = y[i] - y[j];
                int g = __gcd(xx, yy);
                if(g < 0) g = -g; 
                xx /= g, yy /= g;
                S.insert({xx, yy});
            }
        cout << S.size() << "\n";
        return 0;
    }
    

    E - Just one

    给定 \(n\) 个点 \(m\) 条边的简单无向图,每一条边可以给定一个方向,共有 \(2^m\) 中方案,统计每个点有且只有一条出边的方案数。

    若某个连通分支只有单个环,贡献为 \(2\) , 其他情况均不合法,

    问题转化为求只有单个环的联通分支个数 \(t\) , 答案即为 \(2^t\)

    如何判断一个连通分支是否是单个环: 若无环,则 \(n\) 个点的分支有 \(n - 1\) 条边;若有一个环,则边数 \(+1\),有 \(n\) 条边;若有多个环,边数 \(\ge n\) ; 故只需要判断该联通分支点数和边数是否相等即可

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
     
    const int N = 2e5 + 20;
    const int P = 998244353;
     
    int n, m;
    vector<int> G[N];
    bool st[N];
    int point, edge;
     
    void DFS(int u)
    {
        point ++;
        edge += G[u].size(); 
        st[u] = true;
        for(auto v : G[u])
            if(!st[v])
                DFS(v);
    }
     
    int main()
    {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin >> n >> m;
        for(int i = 1; i <= m; ++ i)
        {
            int a, b; 
            cin >> a >> b;
            G[a].push_back(b);
            G[b].push_back(a);
        }
        int ans = 1;
        for(int i = 1; i <= n; ++ i)
            if(!st[i])
            {
                point = edge = 0;
                DFS(i);
                if(point * 2 == edge) ans = 2ll * ans % P;
                else ans = 0;
            }
        cout << ans << "\n";
        return 0;
    }
    

    F - Score of Permutations

    对于一个给定的排列 \(P = (p_1, p_2, ..., p_n)\), 定义 \(S(P)\) 为:

    初始时刻,每个人手中有一个球,每经过一轮,第 \(i\) 个人把手上的球传给 \(p_i\), \(S(P)\) 为至少经过一轮,每个人初始的球重新回到各自手上的最少轮数。

    \(S_n\)\((1, 2, ..., N)\) 的所有排列,求\(\sum\limits_{P\in S_n}S(P)^k \; mod\; 998244353\)

    首先考虑对于一个排列 \(P\) , 如何计算它的 \(S(P)\) , 从 \(i\)\(p_i\) 连一条边,可以发现球会在每一个环之间循环传递,假设形成了 \(k\) 个环,环的大小分别为 \((c_1,c_2,..., c_k)\), 当所有环都回到初始状态时, 所需的轮数为 \(lcm(c_1, c_2, ..., c_k)\)

    考虑 \(dp\) 计算答案, 令 \(dp[i][j]\) 为给 \(i\) 个人已经分配好在哪个环中,且当前所有环的 \(lcm\)\(j\) 的方案数,转移方程为:

    \[dp[i + x][lcm(j, x)] = dp[i][j] * C_{n- i - 1} ^ {x - 1} * (x - 1)! \]

    对于上述状态转移方程,我们挑出 \(x\) 个人组成一个新的环,为了保证不会重复,可以给每次选出的环有序化,即每次先从剩下的人里面选择一个编号最小的,然后再从剩余的 \(n - i - 1\) 个人中选出 \(x - 1\) 个组成这个大小为 \(x\) 的环,即 \(C_{n - i - 1}^{x - 1}\)。对于选出的 \(x\) 个数,排列共有 \(x!\) 种, 又因为是环,所以有 \((x - 1)!\) 种方案。

    由于 \(lcm\) 过大,状态转移可以用 \(map\) 实现; 初始状态为 \(dp[0][1] = 1\),答案即为 \(\sum dp[n][s] * s^k\)

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    const int P = 998244353;
    const int N = 50 + 5;
    
    LL n, k, fac[N], C[N][N];
    map<LL, LL> dp[N];
    
    LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }
    LL lcm(LL a, LL b) { return a * b / gcd(a, b); }
    LL power(LL a, LL b)
    {
        LL res = 1;
        for(; b; b >>= 1, a = a * a % P)
            if(b & 1) res = res * a % P;
        return res;
    }
    
    int main()
    {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        fac[0] = 1;
        for(int i = 1; i < N; ++ i) fac[i] = fac[i - 1] * i % P;
        for(int i = 0; i < N; ++ i)
            for(int j = 0; j <= i; ++ j)
            {
                if(!j) C[i][j] = 1;
                else C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % P;
            } 
        cin >> n >> k;
        dp[0][1] = 1;
        for(int i = 0; i < n; ++ i)
            for(auto [p, q] : dp[i])
                for(int x = 1; x <= n - i; ++ x)
                {
                    LL& d = dp[i + x][lcm(p, x)];
                    LL t = dp[i][p] * C[n - i - 1][x - 1] % P * fac[x - 1] % P;
                    d = (d + t) % P; 
                }
        LL ans = 0;
        for(auto [p, q] : dp[n])
            ans = (ans + power(p, k) * q % P) % P;
        cout << ans << "\n";
        return 0;    
    }
    

    G - The baggage

    重量为\((1, 2, 3, 4, 5)\) 的包裹分别有 \((A_1, A_2, A_3, A_4, A_5)\) 个, 力气为 \((1, 2, 3, 4, 5)\) 的人分别有 \((B_1, B_2, B_3, B_4, B_5)\) 个,每个人可以拿一个或多个包裹,但总重量能超过他的力气,问这些人能否拿起这些包裹?

    重量大的包裹更难被拿,故先从重量大的包裹开始考虑,策略为先考虑完全使用,再考虑使用完产生更有用的

    重量为 \(5\) 的包裹: 仅能被力气为 \(5\) 的人拿;

    重量为 \(4\) 的包裹: 先考虑被力气为 \(4\) 的人拿, 再考虑被力气为 \(5\) 的人拿;

    重量为 \(3\) 的包裹: 先考虑被力气为 \(3\) 的人拿,再考虑被力气为 \(5\) 的人拿, 最后考虑被力气 \(4\) 的人拿(产生 \(2\) 比产生 \(1\) 更优)

    重量为 \(2\) 的包裹: 从 \(5\)\(2\) 尝试即可;

    重量为 \(1\) 的包裹: 从 \(5\)\(1\) 尝试即可;

    若最后没有剩余包裹,既合法,否则非法

    Sample Code (C++)
    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    int n;
    LL A[6], B[6];
    
    void solve(int i, int j)
    {
        LL c = min(A[i], B[j]);
        A[i] -= c;
        B[j] -= c;
        B[j - i] += c;
    }
    
    int main()
    {
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        int __; cin >> __;
        while(__ -- )
        {
            for(int i = 1; i <= 5; ++ i) cin >> A[i];
            for(int i = 1; i <= 5; ++ i) cin >> B[i];
            solve(5, 5);
            solve(4, 4);
            solve(4, 5);
            solve(3, 3);
            solve(3, 5);
            solve(3, 4);
            for(int i = 5; i >= 2; -- i) solve(2, i);
            for(int i = 5; i >= 1; -- i) solve(1, i);
            bool ok = true;
            for(int i = 1; i <= 5; ++ i)
                if(A[i] > 0) ok = false;
            cout << (ok ? "Yes" : "No") << "\n";
        }
        return 0;
    }
    
  • 相关阅读:
    css样式初始化代码总结
    linux LVM逻辑卷的创建,扩容,缩减和删除
    MAC Jenkins安装 + Xcode + 蒲公英 + Testflight
    Linux rsyslog工具
    linux 中 Vi 和 Vim 的使用
    Zabbix实战--监控Nginx、MySQL与VM esxi主机、vSphere Client、JAVA应用
    Linux下netstat命令详解
    Debian 10上使用UFW设置防火墙
    开源网络安全检测工具——伏羲 Fuxi-Scanner
    CentOS8的web终端-cockpit,通过Cockpit管理KVM虚拟机
  • 原文地址:https://www.cnblogs.com/ooctober/p/15569342.html
Copyright © 2020-2023  润新知