• Codeforces Round #604 (Div. 2)


    https://codeforces.com/contest/1265

    这场的2E是1C的不带checkpoints的版本。

    A - Beautiful String

    题意:给一个由'a','b','c','?'组成的字符串,把'?'填成前面三种其中之一使得字符串中没有连续两个相同的字符。

    首先把本身就非法的、全部都是问号的,以及所有的单独的一个问号解决掉,那么剩下的字符串必定满足:至少有一个非问号字符,且没有两个连续的非问号字符,且没有单独的问号,这样是一定有解的,构造如下。

    那么假如有:

    "??aba???bc???bcb???"

    那么等价于:

    "a?aba??abc??cbcb??b"

    意思是每段至少2个连续的问号里的第1个问号变成问号之后的第一个字符,若这段是最后一段问号则把最后一个问号变成其前一个。

    剩下的一段都填两端没有的字符。

    char s[MAXN + 5];
    int nxt[MAXN + 5];
    
    char ch[128][128], ch2[128][2];
    
    void init() {
        memset(ch, '?', sizeof(ch));
        ch['a']['a'] = 'b';
        ch['a']['b'] = 'c';
        ch['a']['c'] = 'b';
        ch['b']['a'] = 'c';
        ch['b']['b'] = 'a';
        ch['b']['c'] = 'a';
        ch['c']['a'] = 'b';
        ch['c']['b'] = 'a';
        ch['c']['c'] = 'a';
        ch2['a'][0] = 'b';
        ch2['a'][1] = 'c';
        ch2['b'][0] = 'a';
        ch2['b'][1] = 'c';
        ch2['c'][0] = 'a';
        ch2['c'][1] = 'b';
    }
    
    void test_case() {
        scanf("%s", s + 1);
        int n = strlen(s + 1);
        for(int i = 2; i <= n; ++i) {
            if(s[i] != '?' && s[i - 1] != '?' && s[i] == s[i - 1]) {
                puts("-1");
                return;
            }
        }
        //上面去除了本身非法的情况,剩下的是一定能构造的
        bool suc = 1;
        for(int i = 1; i <= n; ++i) {
            if(s[i] != '?') {
                suc = 0;
                break;
            }
        }
        if(suc) {
            for(int i = 1; i <= n; ++i)
                putchar('a' + (i & 1));
            putchar('
    ');
            return;
        }
        //上面去除了全部都是'?'的情况
        for(int i = 1; i <= n; ++i) {
            if(s[i] == '?') {
                if(i == 1)
                    s[1] = ch[s[2]][s[2]];
                else if(i == n)
                    s[n] = ch[s[n - 1]][s[n - 1]];
                else
                    s[i] = ch[s[i - 1]][s[i + 1]];
            }
        }
        //上面去除了单独的'?'
        if(s[n] == '?') {
            int i = n - 1;
            while(s[i] == '?')
                --i;
            s[n] = s[i];
        }
        //上面保证了末尾一定不是'?'
        int pos = -1;
        for(int i = n; i >= 1; --i) {
            if(s[i] != '?') {
                pos = i;
                nxt[i] = -1;
            } else
                nxt[i] = pos;
        }
        for(int i = 1; i <= n; ++i) {
            if((i == 1 || s[i - 1] != '?') && s[i] == '?') {
                //每段的第一个问号,假如他前面
                if(i >= 1 && s[i - 1] == s[nxt[i]])
                    continue;
                else
                    s[i] = s[nxt[i]];
            }
        }
        //上面保证了每个问号的前后都是相同的
        for(int i = 1; i <= n; ++i) {
            if(s[i] == '?') {
                for(int j = i; j < nxt[i]; ++j)
                    s[j] = ch2[s[i - 1]][j & 1];
                i = nxt[i] - 1;
            }
        }
        puts(s + 1);
    }
    

    但是实际上!连续三个字符怎么会有重复的呢?随便填就完事了。签到题都是怎么暴力怎么来的,一定是自己想复杂了。

    char s[MAXN + 5];
    
    void test_case() {
        scanf("%s", s + 1);
        int n = strlen(s + 1);
        for(int i = 2; i <= n; ++i) {
            if(s[i] != '?' && s[i - 1] != '?' && s[i] == s[i - 1]) {
                puts("-1");
                return;
            }
        }
        //上面去除了本身非法的情况,剩下的是一定能构造的
        bool suc = 1;
        for(int i = 1; i <= n; ++i) {
            if(s[i] == '?') {
                for(char c = 'a'; c <= 'c'; ++c) {
                    bool suc = 1;
                    s[i] = c;
                    if(i > 1 && s[i] == s[i - 1])
                        suc = 0;
                    if(i < n && s[i] == s[i + 1])
                        suc = 0;
                    if(suc)
                        break;
                }
            }
        }
        puts(s + 1);
    }
    

    B - Beautiful Numbers

    题意:给一个数组是一个[1,n]的permutation。对每个m∈[1,n]问[1,m]是否连续存在在这个数组中。

    题解:

    首先,[1,1]一定存在。

    然后向指定方向扩展到2,若经过2以外的数,把2标记为不存在。

    3已经被扩展,或3在区间左右?是:否。

    所以每次就问新的数是不是在已有区间中或者左右,是则包含,否则扩展到有为止。

    int pos[MAXN + 5];
    
    void test_case() {
        int n;
        scanf("%d", &n);
        for(int i = 1, ai; i <= n; ++i) {
            scanf("%d", &ai);
            pos[ai] = i;
        }
        int l = n + 1, r = 0;
        for(int i = 1; i <= n; ++i) {
            l = min(l, pos[i]);
            r = max(r, pos[i]);
            putchar('0' + (r - l + 1 == i));
        }
        putchar('
    ');
    }
    

    事实上判断一下区间的长度就可以了。

    C - Beautiful Regional Contest

    题意:给一场Regional发奖牌,奖牌分为氪金牌g、卖银牌s和炼铜牌b三种。,要求满足以下条件:

    1、g>0&&s>0&&b>0
    2、g<s&&g<b
    3、g+s+b<=n/2

    同题数的同牌,每个等级都比下一等级至少多一题(区分度极高)。

    在此基础上IUPC当然要扩大赛区规模,最好搞到400个队!这样就可以装满一列火车然后在火车站比赛了。主办方要求尽可能多发牌。

    题解:

    首先最麻烦的条件是“尽可能多发牌”,否则直接贪心:同第一名的全部金,然后发银直到比金多,然后发铜直到比金多。假如可以使得b>g&&g+s+b<=n/2则这个是发票数最小的一个解。

    已知假如发牌数一定,把若奖牌跨至少两种题数,那么降级它会更好,因为g->s更容易使得g<s,而在s>=g的前提下可以尽可能补充b的数量。

    所以直接找到最后一个可以发牌的人,这样发的奖牌是尽可能多的,也是最大可能满足g>0&&s>0&&b>0的,然后在此基础上发最少的g,最大可能满足g<s&&g<b,在s>=g后尽可能发b最大可能满足g<s&&g<b。显然这样是最容易符合题意的一种构造。

    int a[MAXN + 5];
    
    void test_case() {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        int last = n / 2;
        if(a[last] == a[last + 1]) {
            while(last - 1 >= 1 && a[last - 1] == a[last])
                --last;
            --last;
        }
        int g = 0, s = 0, b = 0, i = 1, j;
        j = i;
        for(; i <= last; ++i) {
            if(a[i] == a[j])
                ++g;
            else
                break;
        }
        j = i;
        for(; i <= last; ++i) {
            if(a[i] == a[j])
                ++s;
            else if(s <= g) {
                j = i;
                ++s;
            } else
                break;
        }
        b = last - i + 1;
        if(b <= g) {
            printf("0 0 0
    ");
            return;
        }
        printf("%d %d %d
    ", g, s, b);
    }
    

    D - Beautiful Sequence

    题意:给出0,1,2,3,这4种数字的数量,适当排列他们使得相邻元素的差恰好为1。无解-1。

    题解:

    首先观察一个等价性:

    0 1 2 3 2 1' 2' 3
    

    等价于

    0 1 2 1' 2' 3 2 3
    

    也等价于

    0 1' 2' 1 2 3 2 3
    

    事实上一组元素可以类似这样穿行,但是不知道怎么严格证明。所以合法的构造等价于[0,1][1,2][2,3]这样堆在一起。

    补充:证明:(1,2)的左边可以接(1,0),也可以接(1,2),也可以接(3,2),事实上满足奇偶就可以,右边同理。那么把原本的元素编组出这些接口之后,(1,2)可以在其中任意活动,所以不妨全部丢在中间,左边可能会有多出来的接口(0),右边可能有多出来的接口(3),最后一定满足:(0)(1,0)(1,0)...(1,2)(1,2)...(3,2)(3,2)(3)。注意合法的条件就是中间至少有一个(1,2)

    所以说一开始的想法就是对的,直接这样贪。

    所以可以枚举是0开头还是1开头,两种之一就是答案,或者分析他们的数量关系严格构造:以上面的例子为例把所有的[0,1](必须以1结尾)和[2,3](必须以2开头)取出,剩下的一定是若干对(2,1),若1多1个可以把这个1插在最前面的0的前面,若2多1个可以把这个2插在最后面的3后面。其他情况无解。

    当然当时我是先讨论掉没有0或者没有3的简单情况的。

    注意上面这个算法的条件是可以形成若干个这样的接口,而接口的条件要1不比0少且2不比3少。

    假如不做这个分类讨论,则要改为判定接口是否成功生成,若生成则必须接上。(其实是真的煞笔,一定是要一半奇数一半偶数的,然后奇数偶数隔着放,肯定是尽可能把差值近的丢在一起,然后特判一下是不是有0到3的情况就行了)

    int s[MAXN + 5];
    
    void test_case() {
        int a[4];
        scanf("%d%d%d%d", &a[0], &a[1], &a[2], &a[3]);
        if(a[0] > a[1] + 1 || a[3] > a[2] + 1) {
            puts("NO");
            return;
        }
        if(a[0] == a[1] + 1 && (a[2] + a[3] != 0)) {
            puts("NO");
            return;
        }
        if(a[3] == a[2] + 1 && (a[1] + a[0] != 0)) {
            puts("NO");
            return;
        }
        int n = a[0] + a[1] + a[2] + a[3];
        if(a[1] - a[0] == a[2] - a[3] || a[1] - a[0] + 1 == a[2] - a[3]) {
            int i;
            for(i = 1; a[0]--; i += 2)
                s[i] = 0;
            for(; a[2]--; i += 2)
                s[i] = 2;
            for(i = 2; a[1]--; i += 2)
                s[i] = 1;
            for(; a[3]--; i += 2)
                s[i] = 3;
            puts("YES");
            for(int i = 1; i <= n; ++i)
                printf("%d%c", s[i], " 
    "[i == n]);
            return;
        }
        if(a[1] - a[0] == a[2] - a[3] + 1) {
            int i;
            for(i = 1; a[1]--; i += 2)
                s[i] = 1;
            for(; a[3]--; i += 2)
                s[i] = 3;
            for(i = 2; a[0]--; i += 2)
                s[i] = 0;
            for(; a[2]--; i += 2)
                s[i] = 2;
            puts("YES");
            for(int i = 1; i <= n; ++i)
                printf("%d%c", s[i], " 
    "[i == n]);
            return;
        }
        puts("NO");
        return;
    }
    

    2E - Beautiful Mirrors

    这个是1C的不带checkpoints的版本。

    题意:有n个格子,你从1号格子开始走,在格子i上面有pi的概率往i+1走,若走到n+1就结束,否则回到1号重来。求结束的期望步数。

    题解:设dp[i]表示从第i个格子开始走,到结束的期望步数,则答案为dp[1]。

    若设 (dp_{n+1}=0) ,则对所有的i都有:

    (dp_{i}=p_{i}(1+dp_{i+1})+(1-p_{i})(1+dp_{1}))

    即:
    (dp_{i}=1+p_{i}dp_{i+1}+(1-p_{i})dp_{1})

    特别的:
    (dp_{1}=1+p_{1}dp_{2}+(1-p_{1})dp_{1})

    即:
    (dp_{1}=frac{1}{p_{1}}+dp_{2})

    然后:
    (dp_{2}=1+p_{2}dp_{3}+(1-p_{2})dp_{1})

    即:
    (dp_{2}=1+p_{2}dp_{3}+(1-p_{2})(frac{1}{p_{1}}+dp_{2}))

    (dp_{2}=frac{1+p_{1}-p_{2}}{p_{1}p_{2}}+dp_{3})

    (dp_{2}=frac{q_2+p_{1}}{p_{1}p_{2}}+dp_{3})

    再算出:

    (dp_{3}=frac{q_3(2p_1+p_2)+p_1p_2}{p_{1}p_{2}p_3}+dp_{4})

    太难算了。

    问了一下群友,群友给了一个看不懂的方程。

    假如设从1开始第一次走到第i个格子的期望天数是dp[i],那么

    (dp[1]=0)

    从第i个格子走到第i+1个格子,有p[i]的概率成功此时支付dp[i]+1,有q[i]的概率失败,此时已经支付了dp[i]+1,然后在1,从1到i+1的价格恰好就是dp[i+1]进入套娃。

    假如粗暴一点,失败的就付出已支付的成本,然后转回来?

    (dp[i+1]=p[i](dp[i]+1)+q[i](dp[i]+1+dp[i+1]))

    (p[i]dp[i+1]=p[i](dp[i]+1)+q[i](dp[i]+1))

    (dp[i+1]=frac{1}{p[i]}(dp[i]+1))

    过了第二个样例了?那就这样写。AC全靠猜?大力套样例?

    ll p[MAXN + 5];
    ll dp[MAXN + 5];
    
    const ll inv100 = qpow(100, MOD - 2);
    
    void test_case() {
        int n;
        scanf("%d", &n);
        dp[1] = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%lld", &p[i]);
            p[i] = p[i] * inv100 % MOD;
            dp[i + 1] = qpow(p[i], MOD - 2) * (dp[i] + 1) % MOD;
        }
        printf("%lld
    ", dp[n + 1]);
    }
    

    1C - Beautiful Mirrors with queries

  • 相关阅读:
    ueditor PHP版本使用方法
    PHP三维优先级运算
    navicate for mysql中的sql存放位置和备份
    wamp配置步骤
    phpeclipse xdebug 配置配置 -摘自网络
    xls 和 xml 数据 排序 绑定 -原创
    XSLT教程 比较全的 -摘自网络
    XPath在asp.net中查询XML -摘自网络
    windows上zend server安装 报The server encountered an internal error or misconfiguration and was unable to complete your request -解决方法 摘自网络
    开源项目 配置管理软件推荐
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/11993944.html
Copyright © 2020-2023  润新知