• Educational Codeforces Round 74 (Rated for Div. 2)


    跳过了一些困难的题开一场新的。看来2100的题还是要慢慢挑战,不能操之过急。

    A - Prime Subtraction

    题意:给两个数x,y,可以从x中减去任意个相同的质数p,问能不能与y相等。

    题解:首先x>=y,然后差值不能为1,否则一定可以。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    void test_case() {
        ll x, y;
        scanf("%lld%lld", &x, &y);
        if(x < y || x == y + 1)
            puts("NO");
        else
            puts("YES");
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        scanf("%d", &t);
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    B - Kill 'Em All

    题意:x正半轴上有n个怪物,分别在xi处。每次可以发射一颗导弹,命中位置的怪物被秒杀,其他怪物会被推向两边(位移为r),被推到非负半轴的也会被秒杀。求最少的导弹。

    题解:假如没有“被推到非负半轴的也会被秒杀”,那么数量就是怪物离散化坐标的数量,现在要充分利用这个条件,显然要把怪物从最右边开始推过去。记录累计的导弹数量就可以了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
     
    const int MAXN = 1e5;
    int a[MAXN + 5];
     
    void test_case() {
        int n, r;
        scanf("%d%d", &n, &r);
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        sort(a + 1, a + 1 + n);
        n = unique(a + 1, a + 1 + n) - (a + 1);
        int suml = 0, cnt = 0;
        for(int i = n; i >= 1; --i) {
            if(a[i] > suml) {
                ++cnt;
                suml += r;
            } else
                break;
        }
        printf("%d
    ", cnt);
    }
     
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        scanf("%d", &t);
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    C - Standard Free2play

    题意:你的游戏角色站在h层高的平台,当你站在平台上时,你必须拉动开关使得当前平台及他的下一层平台的伸出/收起状态改变,然后你可以落下至多2层。你可以用水晶改变除了h层的每个平台的初始状态。求最少的水晶。

    题解:看起来像dp,设dp[i]表示从h层下到第i层的需要的最小花费。转移非常显然。但是h太大了。然后显然的假如h下面一直都没有东西,角色可以一直拉动开关降到地面。但是当中间有至少一个平台时,会面临自己下方的平台x-1本身是伸出的情况,这时假如再下一层还有平台x-2就可以直接无视然后掉到x-2,否则就要花一颗水晶消除它。所以就是可以一次消灭两个连续的数字中的高的那个,然后从低的那个继续开始。简化问题可以把0层也作为一块伸出的平台。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 2e5;
    int p[MAXN + 5];
    
    void test_case() {
        int h, n;
        scanf("%d%d", &h, &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d", &p[i]);
        if(n == 1) {
            printf("0
    ");
            return;
        }
        int cnt = 0, cur = h;
        p[n + 1] = 0;
        for(int i = 2; i <= n; ++i) {
            cur = p[i] + 1;
            if(p[i] == p[i + 1] + 1) {
                cur = p[i + 1];
                ++i;
            } else
                ++cnt;
        }
        printf("%d
    ", cnt);
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        scanf("%d", &t);
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    D - AB-string

    题意:一个只由AB组成的字符串s,定义一个字符串是好的,当它每个字母都至少属于一个长度>1的回文串。求s的好的子串的数量。

    题解:模拟一下题意,发现不好的长度>1串必须满足这四种形式:

    AA...AB
    BB...BA
    ABB...B
    BAA...A

    分几种情况统计,第一种统计连续A的数量,遇到B的时候统计;第二种同理;第三种,统计前一个字母是A的连续B的数量,在这个连续B结束(遇到A/遇到字符串结尾)时统计,第四种同理。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 3e5;
    char s[MAXN + 5];
    ll dp[MAXN + 5][4];
    
    void test_case() {
        int n;
        scanf("%d%s", &n, s + 1);
        if(n == 1) {
            puts("0");
            return;
        }
        ll cnt = 0;
        dp[1][0] = (s[1] == 'A');
        dp[1][1] = (s[1] == 'B');
        dp[1][2] = 0, dp[1][3] = 0;
        for(int i = 2; i <= n; ++i) {
            if(s[i] == 'A') {
                dp[i][0] = dp[i - 1][0] + 1;
                dp[i][1] = 0;
                dp[i][2] = dp[i - 1][2] ? dp[i - 1][2] + 1 : s[i - 1] != s[i];
                dp[i][3] = 0;
                cnt += dp[i - 1][1];
                cnt += dp[i - 1][3] - (dp[i - 1][3] >= 1);
            } else {
                dp[i][0] = 0;
                dp[i][1] = dp[i - 1][1] + 1;
                dp[i][2] = 0;
                dp[i][3] = dp[i - 1][3] ? dp[i - 1][3] + 1 : s[i - 1] != s[i];
                cnt += dp[i - 1][0];
                cnt += dp[i - 1][2] - (dp[i - 1][2] >= 1);
            }
            //printf("i=%d
     cnt=%lld
    ",i,cnt);
        }
        cnt += dp[n][2] - (dp[n][2] >= 1);
        cnt += dp[n][3] - (dp[n][3] >= 1);
        printf("%lld
    ", 1ll * n * (n - 1) / 2 - cnt);
    }
    
    int main() {
    #ifdef KisekiPurin
        freopen("KisekiPurin.in", "r", stdin);
    #endif // KisekiPurin
        int t = 1;
        //scanf("%d", &t);
        for(int ti = 1; ti <= t; ++ti) {
            //printf("Case #%d: ", ti);
            test_case();
        }
    }
    

    E - Keyboard Purchase

    题意:你要输入一串n长包含前m个小写英文字母的密码,你要购买一种所有键是m种字母的一个排列的直线的键盘,手指移动的距离就是相邻两个字母的键盘距离的总和。求最小的手指移动距离。

    题解:看见m<=20,假如m<=6岂不是枚举全排列然后暴力验证?可惜改不得。但是这个数据量暗示什么?暗示可以状压,于是口胡一种做法。dp[i][j]表示把状态j中选出的字母全部排在左边,顺序任意,解决前i位密码的最短距离?忽视了一点,这个是有后效性的,前面字母排列的顺序是会影响后面的手指距离的。不懂怎么写,看题解。

    题解也是状压dp,但是是逐个字母加进来的而不是与密码的顺序有关,首先统计出每两个字母的相邻的对数,然后密码就没用了。设dp[j]为把状态j中选出的字母全部排在左边,顺序任意,形成的最短距离。显然的dp[0]=0。考虑加入一种字母x,遍历

    参考资料:

    Educational Codeforces Round 74 Editorial - Codeforces
    Codeforces 1238E. Keyboard Purchase - LLTYYC - 博客园

  • 相关阅读:
    linux下互相传文件的快捷方法
    c语言学习笔记.内存管理.
    c语言学习笔记.结构体.
    格雷码
    c语言学习笔记.指针.
    c语言学习笔记.数组.
    c语言学习笔记.关键字.存储类型关键字等
    leetcode.C.4. Median of Two Sorted Arrays
    Verilog笔记.6.FIFO
    Verilog笔记.5.同步、异步
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/11870120.html
Copyright © 2020-2023  润新知