• Codeforces Round #674 (Div. 3)


    C

    问题描述

    初始状态给你一个 (1),有两种操作

    1. 给其中一个数字增加 1
    2. 复制其中一个数字并添加到该序列中

    问你最少要几次操作,才能得到数字 (n)

    题解

    tag:贪心,枚举

    对于两个操作来说,肯定是 先 (+1) 再复制,得到的数字更大,(因为这个(+1) 操作被复制成了两份),

    否则我们可以替换两个操作之间的顺序,得到更大的值,来逼近目标 (n)

    假定我们一直使用操作一,得到的序列总和为 (x)

    所以就可以枚举 (1sim sqrt {n}) ,对于每个(x) 计算一次答案,取所有结果的(min) 即可

    (1)(x) 需要(x-1) 次操作 ,从 (x) 逼近到 (n) 需要(lceil frac{(n-x)}{x} ceil) 次操作,向上逼近是为了进行余下的第一种操作,比如 (11,5) 这些

    代码

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <map>
    #include <set>
    
    using namespace std;
    #define endl '
    ' 
    #define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef double db;
    typedef pair<int,int> PII;
    
    const int N = 1e5 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const db EXP = 1e-9;
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("D:/scode/in.txt","r",stdin);
        //freopen("D:/scode/out.txt","w",stdout);
    #endif
        IO;
        int _;
        cin >> _;
        while(_--) {
            int n,ans = INF;
            cin >> n;
            for(int i = 1;i <= n / i; ++i) {
                // 向上取整的简单写法 (n - a + (b - 1)) / b;
                ans = min(ans,i - 1 + (n - i + (i - 1)) / i);
            }
            cout << ans << endl;
        }
        return 0;
    }
    

    D

    问题描述

    给你一个序列,问你其中有多少个子段的和为 (0)

    题解

    tag:前缀和

    考虑前缀和,从左到右一直累加到 (presum) 中,如果有两次的(presum) 相等,那么中间肯定有一段 所有值相加为 (0) 的子段

    因为,一直累加(presum) ,不可能从(lsim r) (presum) 不变,(序列中只有正负数,没有 (0)),如果不变,只能是(+0)

    那么我们把重复出现过的(presum)(map) 记录一下就行,注意初始化 (map[0] = 1) ,因为重复出现了 (presum=0) 也算

    代码

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <map>
    #include <set>
    
    using namespace std;
    #define endl '
    ' 
    #define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef double db;
    typedef pair<int,int> PII;
    
    const int N = 1e5 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const db EXP = 1e-9;
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("D:/scode/in.txt","r",stdin);
        //freopen("D:/scode/out.txt","w",stdout);
    #endif
        IO;
        int n,x,ans = 0;
        map<LL,int> m;
        LL sum = 0;
        cin >> n;
        m[0] ++;
        for(int i = 0;i < n; ++i) {
            cin >> x;
            sum += x;
            if(m[sum] > 0) {
                ans ++;
                sum = x;
                // 清空 map
                m.clear();
                m[0] ++;
            }
            m[sum] ++;
        }
        cout << ans << endl;
        return 0;
    }
    

    E

    问题描述

    A 和 B 两个人玩剪刀石头布,一共有 (n)

    已知 A 出了 (a_1) 次石头 (a_2) 次剪刀 (a_3) 次布,(a_1+a_2+a_3=n)

    B同样出了 (b_1,b_2,b_3) 含义一样 (b_1+b_2+b_3=n)

    问 A 最小能赢的次数,A最大能赢的次数

    题解

    tag:贪心,博弈

    A最大能赢的次数就是,用 石头去干剪刀,剪刀去干布,布去干石头,即可,取三者的(min) 值相加

    (min(a_1,b_2) +min(a_2,b_3)+min(a_3,b_1))

    A最小能赢的次数就是,用石头去干布,然后用剩下的次数去干石头,剩下两个同理

    或者计算,总数 - (平局 + 输的最多的次数)= 赢的最少的次数

    (平局 + 输的最多的次数) = (min(a_1,b_1+b_3)) 去最小即可,因为要计算 (a_1) 能被分多少到 (b_1) (平局)和 (b_3) (输局)

    代码

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <map>
    #include <set>
    
    using namespace std;
    #define endl '
    ' 
    #define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef double db;
    typedef pair<int,int> PII;
    
    const int N = 1e5 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const db EXP = 1e-9;
    int n,a[3],b[3];
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("D:/scode/in.txt","r",stdin);
        //freopen("D:/scode/out.txt","w",stdout);
    #endif
        IO;
        cin >> n;
        cin >> a[0] >> a[1] >> a[2];
        cin >> b[0] >> b[1] >> b[2];
        int Amx,Ami = 0;
        Amx = min(a[0],b[1]) + min(a[1],b[2]) + min(a[2],b[0]);
        Ami = n - (min(a[0],b[0] + b[2]) + min(a[1],b[1] + b[0]) + min(a[2],b[2] + b[1]));
        cout << Ami << ' ' << Amx << endl;
        return 0;
    }
    

    F

    问题描述

    给你一个长度为(n) 的字符串,仅包含(a,b,c,?) 这四种字符,其中(?) 可以变成任意一种其他字符 (a,b,c) ,求所有字符串中子序列(abc) 的个数

    题解

    tag:DP

    (f[i][0]) 表示前 (i) 个字符中有多少种序列情况

    (f[i][1]) 表示前(i) 个字符中有多少个 (a)

    (f[i][2]) 表示前(i) 个字符中有多少个(ab)

    (f[i][3]) 表示前(i) 个字符中有多少个(abc)

    如果第(i) 位为(a) ,则 (f[i][1]=f[i-1][1]+f[i-1][0])

    其他同理

    注意,每一个问号都有三种情况,所以一直累乘

    代码是优化成一维的

    代码

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <cstdlib>
    #include <cstring>
    #include <map>
    #include <set>
    
    using namespace std;
    #define endl '
    ' 
    #define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef double db;
    typedef pair<int,int> PII;
    
    const int N = 2e5 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    const db EXP = 1e-9;
    LL f[4];
    // f0 ?
    // f1 a
    // f2 ab
    // f3 abc
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("D:/scode/in.txt","r",stdin);
        //freopen("D:/scode/out.txt","w",stdout);
    #endif
        IO;
        int n;
        char ch;
        cin >> n;
        f[0] = 1;
        while(n --) {
            cin >> ch;
            if(ch == 'a') {
                // 前面的 a 和 ? (也能变成 a )
                f[1] = (f[1] + f[0]) % mod;
            }
            else if(ch == 'b') {
                // 前面的 ab 和 (前面的 a + 当前的 b) == ab 
                f[2] = (f[2] + f[1]) % mod;
            }
            else if(ch == 'c') {
                // 前面的 abc 和 (前面的 ab + 当前的 c) == abc
                f[3] = (f[3] + f[2]) % mod;
            }
            else {
                // 碰到了 ?
                // 从后往前,因为要利用上一层的值,参考01背包的滚动优化
                for(int i = 3;i >= 1;--i) {
                    // 一个 ? 能把当前序列分成三种不同的情况
                    // 前面都一样是 f[i] 第 i 个是问号,可能会是 f[i]'a',f[i]'b',f[i]'c'
                    // 所以 前面的f[i] * 3 ,然后加上 当前这个问号变成 f[i - 1]  
                    f[i] = (f[i] * 3 + f[i - 1]) % mod;
                }
                // 每个 ? 对应一个 * 3
                f[0] = f[0] * 3 % mod;
            }
        }
        cout << f[3] << endl;
        return 0;
    }
    
  • 相关阅读:
    Subclipse安装及应用【eclipse 3.7 + subclipse1.8】
    淘宝有病!
    集装箱货柜号码 公式算法
    自己网站利用支付宝结算时的说明
    发现安全卫士360影响电脑正常运行
    中国银行的动态口令
    c#中的接口(interface)到底应用在哪些地方?
    淘宝有病(二)
    What 's CATT(Computer Aided Test Tool)?How to deal with the CATT in the SAP System?什么是CATT(计算机附加测试工具)
    Consultanting Service
  • 原文地址:https://www.cnblogs.com/lukelmouse/p/13752572.html
Copyright © 2020-2023  润新知