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


    题目链接:https://codeforces.com/contest/1221

    A - 2048 Game

    随便搞搞。

    B - Knights

    题意:在一个n*n的棋盘中,每个格子放一个黑马或者白马。求一种放置方案使得互相攻击的异色马最多。

    题解:奇偶染色。

    C - Perfect Team

    题意:有c个代码手,有m个口胡怪,有x个倒水哥。要求组成尽可能多的三人队,每个三人队至少有一个代码手和一个口胡怪。

    题解:首先先把1:1:1的队伍尽可能配出来,这时如果用完了代码手或者口胡怪,就得到了答案。否则是用完了倒水哥。那么两种极端的情况分别是:全部都是2个代码手配1个口胡怪,全部都是1个代码手配2个口胡怪,这两种直接算出来,剩下的总是有办法配出尽可能多的三人队。

    void TestCase() {
        ll c, m, x;
        scanf("%lld%lld%lld", &c, &m, &x);
        ll ans = 0;
        ll tmp = min(c, m);
        if(x >= tmp)
            ans += tmp;
        else {
            ans += x;
            c -= x;
            m -= x;
            tmp = min(c, m);
            if(c >= 2 * m)
                ans += m;
            else if(m >= 2 * c)
                ans += c;
            else
                ans += (m + c) / 3;
        }
        printf("%lld
    ", ans);
    }
    

    事实上,只需要把c和m强制变成相等,多出来的那些都算作是倒水哥就可以了。

    D - Make The Fence Great Again

    题意:有一个n个数的数组,把第i个数字ai增加1的代价为bi,可以对任意元素增加任意次。求最小的花费使得整个数组没有临位相同。

    题解:看起来只有“临位相同”一个制约条件,那么感觉就是一个dp,而且情况还不多。

    猜想:每个元素其实最多被增加1次。

    设dp[i][j]表示已经完成前i个元素,且第i个元素增加j次的总花费。

    那么:dp[1][0]=0,dp[1][1]=b[1],这个非常简单。后面的会用到吗?

    那么:dp[2][0]=?,若a[1]=a[2],那么只能从dp[1][1]转移,并且显然没有必要从dp[1][2]转移,若a[1]+1=a[2],那么显然只能从dp[1][0]转移,并且显然dp[2][2]也没有意义;dp[2][1]=?,若a[1]=a[2],同理从dp[1][0]转移,若a[1]=a[2]+1,同理从dp[1][1]转移。所以猜想好像是对的?第一个样例都过不了!

    但是这个貌似还是有启示,会不会每个元素最多被增加5次呢?

    int a[300005], b[300005];
    ll dp[300005][6];
    
    void TestCase() {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d%d", &a[i], &b[i]);
        for(int j = 0; j <= 5; ++j)
            dp[1][j] = 1ll * j * b[1];
        for(int i = 2; i <= n; ++i) {
            for(int j = 0; j <= 5; ++j)
                dp[i][j] = LINF;
            for(int j = 0; j <= 5; ++j) {
                for(int k = 0; k <= 5; ++k) {
                    if(a[i - 1] + k == a[i] + j)
                        continue;
                    dp[i][j] = min(dp[i][j], dp[i - 1][k] + 1ll * j * b[i]);
                }
            }
        }
        ll ans = LINF;
        for(int j = 0; j <= 5; ++j)
            ans = min(ans, dp[n][j]);
        printf("%lld
    ", ans);
    }
    

    通过了,这……

    事实上我觉得很有可能最多只会增加2次(因为相邻3个数最多只会占3个连续的位置)。

    int a[300005], b[300005];
    ll dp[300005][3];
    
    void TestCase() {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d%d", &a[i], &b[i]);
        for(int j = 0; j <= 2; ++j)
            dp[1][j] = 1ll * j * b[1];
        for(int i = 2; i <= n; ++i) {
            for(int j = 0; j <= 2; ++j)
                dp[i][j] = LINF;
            for(int j = 0; j <= 2; ++j) {
                for(int k = 0; k <= 2; ++k) {
                    if(a[i - 1] + k == a[i] + j)
                        continue;
                    dp[i][j] = min(dp[i][j], dp[i - 1][k] + 1ll * j * b[i]);
                }
            }
        }
        ll ans = LINF;
        for(int j = 0; j <= 2; ++j)
            ans = min(ans, dp[n][j]);
        printf("%lld
    ", ans);
    }
    

    启示:就算猜想是错的,好像也可以得到一些思路,大胆猜想。

    *E - Game With String

    2400的思维题果然非同一般。

    题意:有一个字符串,只由'X'和'.'构成,Alice和Bob轮流选择一段连续的'.'变成相同长度的'X',Alice每次选择的长度必须是a,Bob每次选择的长度必须是b,保证b<a。求Alice先手是否可以胜利。

    题解:首先,红名爷们观察出一个东西:可以把这些连续的'.'转化成数字,然后忽略所有的'X'。(假设 (a<2b) )然后这些数字x分为下面四种:

    type1. $ 1leq x < b$ 这种串大家都不能放,直接忽略。
    type2. $ bleq x < a$ 这种串是Alice不能操作,但是Bob可以操作的。只要存在至少一个这样长度的串,无论是Alice先手还是Bob先手,Bob可以把这个串留到type3和type4消耗完之后再操作,这样Alice必败。
    type3. $ aleq x < 2b$ 这种串并不是很特别。
    type4. (2bleq x) 这种串当Bob先手时,可以直接把开头的b长度留下来,然后从b+1位置开始把[b+1,2b]换成'X',转化出一个type2和一个随意类型的串,从而Bob达到必胜。

    所以,只有当Alice进行一次先手操作之后,既没有type2也没有type4才有机会赢,也就是若存在type4,这一次先手就要消除所有的type4,也就是type4只能最多1个。当有这个机会时,能有用的串就只有type3,这个时候要看type3的数量的奇偶性。

    综上所述, (a<2b) 时解法应该是:

    1. 判断type2存在?存在就直接No。
    2. 那么type2不存在。判断type4存在?不存在就直接数一数type3的数量的奇偶性,然后Yes/No。
    3. 那么type2不存在,type4存在。判断type4有至少两个?有至少两个则直接No。
    4. 那么type2不存在,type4存在且仅存在一条,设其长度为 (len) 。Alice一定会在 ([b,b+a-1]) 的位置放吗?(不一定,看看切出来的后面一段会是什么)
      枚举Alice的先手操作的位置,然后若有type2或者type4则只能尝试下一个位置,否则判断新的type3的奇偶性,尝试成功则Yes,否则No。

    那么还有一种 (ageq 2b) 的情况,这种情况下分为3种。

    type1. $ 1leq x < b$ 这种串大家都不能放,直接忽略。
    type2. $ bleq x < a$ 这种串是Alice不能操作,但是Bob可以操作的。只要存在至少一个这样长度的串,无论是Alice先手还是Bob先手,Bob可以把这个串留到type3和type4消耗完之后再操作,这样Alice必败。
    type4. (aleq x) 这种串当Bob先手时,可以直接把开头的b长度留下来,然后从b+1位置开始把[b+1,2b]换成'X',转化出一个type2和一个随意类型的串,从而Bob达到必胜。

    也就是说是没有type3,只有一次机会获胜,就是有唯一一段type4,并且存在一种方法使得拿走之后剩下两头都是type1或者长度为0。

    char s[300005];
    int x[300005], xtop;
    
    void TestCase() {
        xtop = 0;
        int a, b;
        scanf("%d%d", &a, &b);
        scanf("%s", s + 1);
        int n = strlen(s + 1);
        int cur = 0;
        for(int i = 1; i <= n; ++i) {
            if(s[i] == 'X') {
                if(cur) {
                    x[++xtop] = cur;
                    cur = 0;
                }
            } else
                ++cur;
        }
        if(cur) {
            x[++xtop] = cur;
            cur = 0;
        }
        if(a >= 2 * b) {
            int cnt_type4 = 0, len = 0;
            for(int i = 1; i <= xtop; ++i) {
                if(x[i] < b)
                    continue;
                else if(b <= x[i] && x[i] < a) {
                    puts("NO");
                    return;
                } else if(a <= x[i]) {
                    ++cnt_type4;
                    len = x[i];
                    if(cnt_type4 >= 2) {
                        puts("NO");
                        return;
                    }
                } else
                    exit(-1);
            }
            if(cnt_type4 == 1) {
                for(int i = 1; i <= len - a + 1; ++i) {
                    int len1 = i - 1, len2 = len - (i + a - 1);
                    if(b <= len1 || b <= len2)
                        continue;
                    puts("YES");
                    return;
                }
                puts("NO");
                return;
            } else {
                puts("NO");
                return;
            }
        } else {
            int cnt_type3 = 0, cnt_type4 = 0, len = 0;
            for(int i = 1; i <= xtop; ++i) {
                if(x[i] < b)
                    continue;
                if(b <= x[i] && x[i] < a) {
                    puts("NO");
                    return;
                } else if(a <= x[i] && x[i] < 2 * b)
                    ++cnt_type3;
                else if(2 * b <= x[i]) {
                    ++cnt_type4;
                    len = x[i];
                    if(cnt_type4 >= 2) {
                        puts("NO");
                        return;
                    }
                }
            }
            if(cnt_type4 == 1) {
                for(int i = 1; i <= len - a + 1; ++i) {
                    int len1 = i - 1, len2 = len - (i + a - 1);
                    if((b <= len1 && len1 < a) || (b <= len2 && len2 < a))
                        continue;
                    if(2 * b <= len1 || 2 * b <= len2)
                        continue;
                    int tmp1 = 0, tmp2 = 0;
                    if(a <= len1 && len1 < 2 * b)
                        tmp1 = 1;
                    if(a <= len2 && len2 < 2 * b)
                        tmp2 = 1;
                    if((cnt_type3 + tmp1 + tmp2) % 2 == 0) {
                        puts("YES");
                        return;
                    }
                }
                puts("NO");
                return;
            } else {
                if(cnt_type3 % 2 == 1) {
                    puts("YES");
                    return;
                } else {
                    puts("NO");
                    return;
                }
            }
        }
        exit(-1);
    }
    
    char s[300005];
    int x[300005], xtop;
     
    void TestCase() {
        xtop = 0;
        int a, b;
        scanf("%d%d", &a, &b);
        scanf("%s", s + 1);
        int n = strlen(s + 1);
        int cur = 0;
        for(int i = 1; i <= n; ++i) {
            if(s[i] == 'X') {
                if(cur) {
                    x[++xtop] = cur;
                    cur = 0;
                }
            } else
                ++cur;
        }
        if(cur) {
            x[++xtop] = cur;
            cur = 0;
        }
        if(a >= 2 * b) {
            int cnt_type4 = 0, len = 0;
            for(int i = 1; i <= xtop; ++i) {
                if(b <= x[i] && x[i] < 2 * b) {
                    puts("NO");
                    return;
                } else if(2 * b <= x[i]) {
                    ++cnt_type4;
                    len = x[i];
                    if(cnt_type4 >= 2) {
                        puts("NO");
                        return;
                    }
                }
            }
            if(cnt_type4 == 1) {
                if(a <= len && len <= 2 * (b - 1) + a) {
                    puts("YES");
                    return;
                } else {
                    puts("NO");
                    return;
                }
            } else {
                puts("NO");
                return;
            }
        } else {
            int cnt_type3 = 0, cnt_type4 = 0, len = 0;
            for(int i = 1; i <= xtop; ++i) {
                if(b <= x[i] && x[i] < a) {
                    puts("NO");
                    return;
                } else if(a <= x[i] && x[i] < 2 * b)
                    ++cnt_type3;
                else if(2 * b <= x[i]) {
                    ++cnt_type4;
                    len = x[i];
                    if(cnt_type4 >= 2) {
                        puts("NO");
                        return;
                    }
                }
            }
            if(cnt_type4 == 1) {
                for(int i = 1; i <= len - a + 1; ++i) {
                    int len1 = i - 1, len2 = len - (i + a - 1);
                    if((b <= len1 && len1 < a) || (b <= len2 && len2 < a))
                        continue;
                    if(2 * b <= len1 || 2 * b <= len2)
                        continue;
                    int tmp1 = 0, tmp2 = 0;
                    if(a <= len1 && len1 < 2 * b)
                        tmp1 = 1;
                    if(a <= len2 && len2 < 2 * b)
                        tmp2 = 1;
                    if((cnt_type3 + tmp1 + tmp2) % 2 == 0) {
                        puts("YES");
                        return;
                    }
                }
                puts("NO");
                return;
            } else {
                if(cnt_type3 % 2 == 1) {
                    puts("YES");
                    return;
                } else {
                    puts("NO");
                    return;
                }
            }
        }
        exit(-1);
    }
    
  • 相关阅读:
    javascript中事件
    pku 1836 Alignment
    pku 3086 Triangular Sums
    [转]asp格式化日期
    用数组作checkboxlist数据源
    (转)Membership、MembershipUser和Roles类 详解
    asp中判断 checkbox 是否选中
    使用 AddRange 方法将多个 ListItem 对象添加到集合
    My97DatePicker,一个兼容所有浏览器的日历选择脚本(相当经典)
    .Net下批量删除数据的存储过程问题(用动态SQL )
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12640383.html
Copyright © 2020-2023  润新知