zoukankan      html  css  js  c++  java
  • Codeforces Round #604 (Div. 2)

    A. Beautiful String (CF 1265 A)

    题目大意

    当没有连续两个字母相同时,该字符串为美丽串,给定一个含(a,b,c,?)的字符串,要求将(?)替换成(a),(b)(c),使得该串为美丽串。若无法成为美丽串输出(-1)

    解题思路

    很显然对于每个(?)的取值只跟它左右两个位置有关,而它一定能取到一个合法的值,只要跟左右不同即可,而如果一开始就有连续两个字母相同则输出(-1).

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    bool qwq;
    
    char s[100500];
    
    void check(int x){
        s[x]='a';
        if (x==0){
            if (s[x+1]=='a') s[x]='b';
        }
        else{
            if (s[x-1]=='a'||s[x+1]=='a') {
                                            s[x]='b';
                                            if (s[x-1]=='b'||s[x+1]=='b') {
                                                                            s[x]='c';
                                                                            if (s[x-1]=='c'||s[x+1]=='c') qwq=false;
                                            }
            }
             
        }
    }
    
    void Input(void) {
        scanf("%s",s);
        int len=strlen(s);
        qwq=true;
        for(int i=0;i<len;++i){
            if (qwq==false) break;
            if (i!=0&&s[i]==s[i-1]) qwq=false;
            if (s[i]=='?') check(i);
        }
        if (!qwq) printf("-1
    ");
        else printf("%s
    ",s); 
    }
    
    void Solve(void) {}
    
    void Output(void) {}
    
    main(void) {
        int kase;
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        read(kase);
        for (int i = 1; i <= kase; i++) {
            //printf("Case #%d: ", i);
            Input();
            Solve();
            Output();
        }
    }
    


    B. Beautiful Numbers (CF 1265 B)

    题目大意

    给定一个排列,求每一个(mleq n),是否存在(l,r)使得区间(left[ l,r ight])(1)~(m)的一个全排列,存在则(m)为美丽数字。输出一个数字串,第(i)个数字表示(i)是否是美丽数字,是则(1),否则(0)

    解题思路

    (m=1)的时候我们选择(1)的位置,然后我们从(1)的位置进行拓展,很显然我们每一次贪心的向左右两个数中较小的那个数进行扩展,才有可能得到一个(1)~(m)的全排列。

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    int n,l,r,pos,cnt,mi,ma;
    
    const int N=2e5+8;
    
    int p[N];
    
    void Input(void) {
        read(n);
        for(int i=1;i<=n;++i) {
            read(p[i]);
            if (p[i]==1) pos=i;
        }
    }
    
    void Solve(void) {
        p[0]=p[n+1]=3e6;
        l=r=pos;
        cnt=1;
        mi=ma=1;
        putchar('1');
        while(cnt<n){
            if (l==1){
                ++r;
                ++cnt;
                ma=MAX(ma,p[r]);
            }else if (r==n){
                --l;
                ++cnt;
                ma=MAX(ma,p[l]);
            }else if (p[l-1]>p[r+1]) {
                ++r;
                ++cnt;
                ma=MAX(ma,p[r]);
            }
            else{
                --l;
                ++cnt;
                ma=MAX(ma,p[l]);
            }
            if (cnt==ma-mi+1) putchar('1'); 
            else putchar('0');
        }
        puts("");
    }
    
    void Output(void) {}
    
    main(void) {
        int kase;
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        read(kase);
        for (int i = 1; i <= kase; i++) {
            //printf("Case #%d: ", i);
            Input();
            Solve();
            Output();
        }
    }
    


    C. Beautiful Regional Contest (CF 1265 C)

    题目大意

    (n)个选手参加比赛,递减给出它们解决的题数,分配(g)个金牌(s)个银牌和(b)个铜牌,要求(g<s)(g<b),且(g+s+bleq dfrac {n}{2}),且获得金牌的选手的题数严格大于获得银牌选手的题数,获得银牌的选手题数严格大于获得铜牌选手的题数,获得铜牌的选手题数严格大于获得铁牌(无牌)(来杯拿铁咖啡)选手的题数,问能否做到,若能,给定一个可行的分配方案,使得发牌数最大。

    解题思路

    题目对于(g)有大小限制而(s)(b)之间没有,则我们让(g)尽可能小就好了,即选解题数最高的那一组选手全部发金牌,然后发银牌,直到(g>s),剩下的选手全部发铜牌,直到发的牌数恰好小于(dfrac {n}{2})即可,做不到则不可行。
    如果你是良心比赛方可以最后把(s)(b)调换一下。

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    int n,g,s,b,qwq,re;
    
    const int N=4e5+8;
    
    int num[N],cnt[N];
    
    void Input(void) {
        qwq=0;
        num[0]=-1;
        read(n);
        for(int a,i=1;i<=n;++i) {
            read(a);
            if (num[qwq]!=a) num[++qwq]=a;
            ++cnt[qwq];
        }
        s=g=b=re=0;
    }
    
    void Solve(void) {
        g=cnt[1];
        int i=2;
        while(s<=g) s+=cnt[i++];
        while(b<=g) b+=cnt[i++];
        if (s+g+b>n/2) g=s=b=0;
        else {while(s+g+b<=n/2) b+=cnt[i++]; b-=cnt[--i];}
        printf("%d %d %d
    ",g,s,b);
        for(int i=1;i<=n;++i) num[i]=cnt[i]=0;
    }
    
    void Output(void) {}
    
    main(void) {
        int kase;
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        read(kase);
        for (int i = 1; i <= kase; i++) {
            //printf("Case #%d: ", i);
            Input();
            Solve();
            Output();
        }
    }
    


    D. Beautiful Sequence (CF 1265 D)

    题目大意

    给了(a)(0)(b)(1)(c)(2)(d)(3),要求排成一个序列,使得俩俩差值为(1),输出任意符合要求序列即可,没有则(NO)

    解题思路

    • 如果有三个数是(0)个,则第四个数数量为(1)则可行,否则不可行。
    • 如果有两个数是(0)个,则看另外两个数的差值是否为(1),是则由植树原理再判断二者的差值是否为一,是则可行,其余情况均不可行。
    • 如果有一个数是(0)个,则看这个数是多少,若为(1)(2)则不可行,当为(0)(3)时,不失一般性,假设是(0)的数为(0)个,那么我们排列(1),(2),(3),由植树原理可知如果(cnt=c-left( b-1+d-1+1 ight) leq 2)则可行,即(1,2,1,2,1,2......,2,1, 2, 3,2,3,2......2,3,)如此排列,若(cnt)(1)则在序列最左边放一个(2),若为(2)则在最左边和最右边各放一个(2)即可。
    • 如果有零个数是(0)个,我们考虑(0,1)(2,3),首先(bgeq a)(cgeq d),否则不可行。我们按照,(0,1,0,1......)(......2,3,2,3)如此排好后,考虑(1)(2)之间的排列,我们如此(2,1,2,1.....)排列,直到用光(1)或者(2),此时如果还有剩余的,假设(1)还有剩余,若剩余(1)个,则放到最左边,否则不可行,若(2)还有剩余,若剩余(1)个,则放到最右边,否则不可行.

    综上即可。

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    int a,b,c,d,mi,cnt;
    
    bool qwq;
    
    void Input(void) {
        cnt=0;
        read(a);
        read(b);
        read(c);
        read(d);
        cnt=(a==0)+(b==0)+(c==0)+(d==0);
    }
    
    void check1(){
        int sign=0;
        if (a==0) sign=0;
        else if (b==0) sign=1;
        else if (c==0) sign=2;
        else sign=3;
        if (sign==1||sign==2){
            qwq=true;
            return;
        }
        if (sign==3){
            b-=a-1;
            b-=c-1;
            --b;
            if (b<0||b>2){
                qwq=true;
                return;
            }
            else{
                printf("YES
    ");
                if (b) --b,printf("1 ");
                for(int i=1;i<=a;++i) printf("0 1 ");
                for(int i=1;i<c;++i) printf("2 1 ");
                printf("2");
                if (b) printf(" 1
    ");
                else printf("
    ");
                return;
            }
        }
        else{
            c-=b-1;
            c-=d-1;
            --c;
            if (c<0||c>2){
                qwq=true;
                return;
            }
            else{
                printf("YES
    ");
                if (c) --c,printf("2 ");
                for(int i=1;i<=b;++i) printf("1 2 ");
                for(int i=1;i<d;++i) printf("3 2 ");
                printf("3");
                if (c) printf(" 2
    ");
                else printf("
    ");
                return;
            }
        }
    }
    
    void check2(){
        int s1=-1,s2=-1;
        int cnt[4];
        cnt[0]=a;
        cnt[1]=b;
        cnt[2]=c;
        cnt[3]=d;
        if (a!=0) s1=0;
        if (b!=0) if (s1==-1) s1=1;else s2=1;
        if (c!=0) if (s1==-1) s1=2;else s2=2;
        if (d!=0) if (s1==-1) s1=3;else s2=3;
        if (s2-s1>1) {
            qwq=true;
            return;
        }
        else{
            if (ABS(cnt[s2]-cnt[s1])>1){
                qwq=true;
                return;
            }
            else{
                printf("YES
    ");
                if (cnt[s2]>cnt[s1]) {for(int i=1;i<=cnt[s1];++i) printf("%d %d ",s2,s1); printf("%d
    ",s2);}
                else if (cnt[s2]<cnt[s1]) {for(int i=1;i<=cnt[s2];++i) printf("%d %d ",s1,s2); printf("%d
    ",s1);}
                else for(int i=1;i<=cnt[s1];++i) printf("%d %d%c",s1,s2,i==cnt[s1]?'
    ':' ');
                return;
            }
        }
    }
    
    void check3(){
        int si=0;
        int cnt[4];
        cnt[0]=a;
        cnt[1]=b;
        cnt[2]=c;
        cnt[3]=d;
        for(int i=0;i<4;++i) if (cnt[i]!=0) si=i;
        if (cnt[si]==1){
            printf("YES
    ");
            printf("%d
    ",si);
            return;
        }
        else {
            qwq=true;
            return;
        }
    }
    void Solve(void) {
        qwq=false;
        if (a>b&&(c!=0||d!=0)) qwq=true;
        else if (d>c&&(b!=0||a!=0)) qwq=true;
        if (!qwq){
            if (cnt==0){
            b-=a;
            c-=d;
            mi=MIN(b,c);
            b-=mi;
            c-=mi;
            if (b==1||c==1){
                printf("YES
    ");
                if (b==1) {
                    printf("1 ");
                    for(int i=1;i<=a;++i) printf("0 1 ");
                    for(int i=1;i<=mi;++i) printf("2 1 ");
                    for(int i=1;i<=d;++i) printf("2 3%c",i==d?'
    ':' ');
                }
                else{
                    for(int i=1;i<=a;++i) printf("0 1 ");
                    for(int i=1;i<=mi;++i) printf("2 1 ");
                    for(int i=1;i<=d;++i) printf("2 3 "); 
                    printf("2
    ");
                }
            }
            else if (b==c){
                    printf("YES
    ");
                    for(int i=1;i<=a;++i) printf("0 1 ");
                    for(int i=1;i<=mi;++i) printf("2 1 ");
                    for(int i=1;i<=d;++i) printf("2 3%c",i==d?'
    ':' '); 
            }
            else qwq=true;
            }
            else{
                if (cnt==1) check1();
                else if (cnt==2) check2();
                else if (cnt==3) check3();
            }
        }
        if (qwq) printf("NO
    ");
    }
    
    void Output(void) {}
    
    main(void) {
        //int kase;
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //read(kase);
        //for (int i = 1; i <= kase; i++) {
            //printf("Case #%d: ", i);
            Input();
            Solve();
            Output();
        //}
    }
    

    由于昨晚放弃思考了所以代码写了巨长……

    E. Beautiful Mirrors (CF 1265 E)

    题目大意

    (n)枚镜子,每天问一枚镜子,从第一枚镜子开始问(Creatnx)是否漂亮,是则下一天跳转到下一个镜子,否则下一天从第一枚镜子重新开始问。当最后一枚镜子即第(n)枚镜子说她漂亮时,她就变得很开心。问她变得开心的期望天数。

    解题思路

    期望题,我们通常逆推,即从结果推到初始状态。
    (fleft( i ight))表示从第(i)枚镜子开始问,变得开心(即问到第n枚镜子得到漂亮回答)的期望天数。
    根据期望的定义,我们有(fleft( n+1 ight) =0)以及(fleft( i ight) =dfrac {p_{i}}{100}fleft( i+1 ight) +left( 1-dfrac {p_{i}}{100} ight) fleft( 1 ight))
    即对于第(i)天,它有(dfrac {p_{i}}{100})的概率需要(fleft( i+1 ight))才变得开心,也有(left( 1-dfrac {p_{i}}{100} ight))的概率需要(fleft( 1 ight))才变得开心。
    右式一共有(n)个方程,我们可以用高斯消元即可解出答案(fleft( 1 ight)),但复杂度是(Oleft( n^{3} ight)),会超时。
    由于逆推状态不当,导致式子中存在(fleft( 1 ight)),这对答案求值造成很大不便,我们需要修改状态。
    由于回答不漂亮会回到第一枚镜子,那么我们希望第一枚镜子的状态会是一个已知状态。
    我们设(fleft( i ight))表示从第一枚镜子问,问到第(i)枚镜子且回答漂亮的期望天数。
    (fleft( 0 ight) =0)(fleft( i ight) =fleft( i-1 ight) +dfrac {p_{i}}{100}+left( 1-dfrac {p_{i}}{100} ight) left( fleft( i ight) +1 ight))
    即我们要问第(i)枚镜子,首先需要期望天数(fleft( i-1 ight))问到第(i-1)枚镜子并得到漂亮的回答,然后对于第(i)枚镜子,我们有(dfrac {p_{i}}{100})的概率花一天得到漂亮的回答,也有(left( 1-dfrac {p_{i}}{100} ight))的概率得到不漂亮回答,这时需要再花(fleft( i ight))天才能得到漂亮的回答,所以总共需要(fleft( i ight) +1)(1)是问第(i)枚镜子得到不漂亮的回答的那一天),化简一下即可得到(fleft( i ight) =dfrac {left( fleft( i-1 ight) +1 ight) imes 100}{p_{i}}),递推(Oleft( n ight))即可得到答案(fleft( n ight))
    ((fleft( i ight) =dfrac {p_{i}}{100}cdot left( fleft( i-1 ight) +1 ight) +left( 1-dfrac {p_{i}}{100} ight) cdot left( fleft( i-1 ight) +1+fleft( i ight) ight))这个和上面是等价的,即有(dfrac {p_{i}}{100})的概率得到漂亮答案,这时需要的天数是(fleft( i-1 ight) +1),也有(left( 1-dfrac {p_{i}}{100} ight))的概率得到了不漂亮回答,这时我们需要从第一枚镜子重新问,此时得到第(i)枚镜子的漂亮回答的天数是(left( fleft( i-1 ight) +1+fleft( i ight) ight)))

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    const long long mo=998244353;
    
    long long kuai(long long a,long long b){
        int qwq=1;
        while(b){
            if (b&1) qwq=a*qwq%mo;
            a=a*a%mo;
            b>>=1;
        }
        return qwq;
    }
    
    void Input(void) {
        int n;
        long long ans=0,f;
        read(n);
        for(int i=1;i<=n;++i){
            read(f);
            ans=(ans+1)%mo*100%mo*kuai(f,mo-2)%mo;
        }
        printf("%lld
    ",ans);
    }
    
    void Solve(void) {}
    
    void Output(void) {}
    
    main(void) {
        //int kase;
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //read(kase);
        //for (int i = 1; i <= kase; i++) {
            //printf("Case #%d: ", i);
            Input();
            Solve();
            Output();
        //}
    }
    


    C. Beautiful Mirrors with queries (CF 1264 C)

    题目大意

    (n)枚镜子,每天问一枚镜子,从第一枚镜子开始问(Creatnx)是否漂亮,是则下一天跳转到下一个镜子,否则下一天从小于当前镜子编号的标有(check point)的最大编号的镜子问。当最后一枚镜子即第(n)枚镜子说她漂亮时,她就变得很开心。
    (q)次操作,每次操作将第(i)枚镜子设为(check point)(如果之前不是(check point))或者取消(check point)(如果之前是(check point)),对于每次操作,回答她变得开心的期望天数。

    解题思路

    由于镜子回答不漂亮的时候(Creatnx)不再是从第一枚镜子问,(check point)相当于把连续的镜子分成了若干段,不同段之间互不干扰,对于每一段(left[ l,r ight]),我们都可以假想是从第一枚镜子问到第(r-l+1)枚镜子并得到漂亮回答的期望天数,由期望的线性可加性,我们把不同段的期望天数相加即可得到答案。而每次操作仅仅增加或移除一个(check point),如果我们能够快速知道某段区间对答案贡献的期望天数,即可快速解决此题。

    上一题中一开始的递推式(fleft( i ight) =dfrac {p_{i}}{100}fleft( i+1 ight) +left( 1-dfrac {p_{i}}{100} ight) fleft( 1 ight)),某人通过解前几项的规律得出$$fleft( 1 ight) = frac{1 + p_1 + p_1 cdot p_2 + ldots + p_1cdot p_2 cdot ldots cdot p_{n-1}}{p_1cdot p_2 cdot ldots cdot p_n}$$,这是我们从(1)号镜子开始问问到第(n)号镜子并得到漂亮回答的答案。其实这个从后来的递推式(fleft( i ight) =dfrac {left( fleft( i-1 ight) +1 ight)}{p_{i}})展开也可得到。

    这样子的话,对于一个新添加的(check point),记为(mid),再设编号小于(check point)编号的最大(check point)编号为(l),编号大于(check point)编号的最小(check point)编号为(r),则从(1)(l-1)的期望天数,从(r)(n)的期望天数并没有受到影响,而从(l)(r-1)的期望天数被分成了两部分,一部分是从(l)(mid-1),一部分是(mid)(r-1),我们只要减去(l)(r-1)的期望贡献,再加上(l)(mid-1)(mid)(r-1)的期望贡献即可得到新的答案,移除的话即减去(l)(mid-1)(mid)(r-1)的期望贡献,加回(l)(r-1)的期望贡献即可。

    从上面展开递推式的过程(这里没有)我们可以知道,对于从(u)(v)都得到漂亮回答的期望天数为$$frac{1 + p_u + p_u cdot p_{u+1} + ldots + p_u cdot p_{u+1} cdot ldots cdot p_{v-1}}{p_u cdot p_{u+1} cdot ldots cdot p_v} = frac{A}{B}$$,由此我们只要预处理(s_i = p_1 cdot p_2 cdot ldots cdot p_i)以及(t_i = p_1 + p_1 cdot p_2 + ldots + p_1 cdot p_2 ldots cdot p_i),那么对于从(u)(v)都得到漂亮回答的情况,(A = frac{t_{v-1} - t_{u-2}}{p_1cdot p_2 cdotldotscdot p_{u-1}} = frac{t_{v-1} - t_{u-2}}{s_{u-1}})(B = frac{s_v}{s_{u-1}}),二者相除即是期望天数.

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    int n,q;
    
    const int N=2e5+8;
    
    const long long mo=998244353;
    
    long long psum[N],pmul[N],ipmul[N],p[N];
    
    long long ans;
    
    set<long long> mirror;
    
    long long kuai(long long a,long long b){
        long long qwq=1;
        while(b){
            if (b&1) qwq=qwq*a%mo;
            a=a*a%mo;
            b>>=1;
        }
        return qwq;
    }
    void Input(void) {
        read(n);
        read(q);
        long long tmp=kuai(100,mo-2);
        for(int i=1;i<=n;++i){
            read(p[i]);
            p[i]=p[i]*tmp%mo;
        }
    }
    
    long long getans(long long l,long long r){
        long long qwq=0;
        if (l==1) qwq=0;
        else qwq=psum[l-2];
        return (pmul[l-1]*(psum[r-1]-qwq)%mo*ipmul[r]%mo*ipmul[l-1])%mo;
    }
    
    void Solve(void) {
        pmul[0]=1;
        ipmul[0]=1;
        psum[0]=1;
        for(int i=1;i<=n;++i){
            pmul[i]=pmul[i-1]*p[i]%mo;
            psum[i]=(psum[i-1]+pmul[i])%mo;
            ipmul[i]=kuai(pmul[i],mo-2);
        }
        ans=getans(1,n);
        mirror.insert(1);
        mirror.insert(n+1);
        for(int u,i=1;i<=q;++i){
            read(u);
            if (mirror.count(u)){
                auto mid=mirror.find(u);
                auto l=mid,r=mid;
                --l;
                ++r;
                ans-=getans(*l,*mid-1);
                ans-=getans(*mid,*r-1);
                ans+=getans(*l,*r-1);
                mirror.erase(u);
            }
            else{
                auto mid=mirror.insert(u).first;
                auto l=mid,r=mid;
                --l;
                ++r;
                ans+=getans(*l,*mid-1);
                ans+=getans(*mid,*r-1);
                ans-=getans(*l,*r-1);
            }
            ans%=mo;
            while(ans<0) ans+=mo;
            printf("%lld
    ",ans);
        }
    }
    
    void Output(void) {}
    
    main(void) {
        //int kase;
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //read(kase);
        //for (int i = 1; i <= kase; i++) {
            //printf("Case #%d: ", i);
            Input();
            Solve();
            Output();
        //}
    }
    


    F. Beautiful Bracket Sequence (easy version)

    题目大意

    定义一个合法的括号串以及它的深度:

    • 合法的括号串即左括号数量等于右括号数量且对于任意一个左括号(()都能找到一个与之匹配的右括号())
    • 空括号串的深度为(0)
    • 当一个合法括号串(t)的深度为(d),则(left( t ight))括号串的深度为(d+1)
    • 如果有两个合法的括号串(s)(t),则括号串(st)的深度为两者中的较大值

    则对于一个(可能不合法)的括号串,它的深度为它所有合法括号子串(可以不连续)深度的最大值。
    现给定一个含有"(" "?" 和")"括号串,对"?"取所有值("("或")"),求所有情况该括号串深度和。

    解题思路

    我们先解决如何计算一个括号串的深度。
    这是个区间问题,我们定义(dpleft[ i ight] left[ j ight])表示(sleft[ i...j ight])的深度
    如果(s[i] = ()(s[j] = ))或者其中有一个或两个是(?),那么(dpleft[ i ight] left[ j ight] =dpleft[ i+1 ight] left[ j-1 ight] +1)
    否则(dpleft[ i ight] left[ j ight] =maxleft( dpleft[ i+1 ight] left[ j ight],dpleft[ i ight] left[ j-1 ight] ight))
    这就解决了深度的问题。
    从中我们考虑每对括号对答案的贡献,即设(dpleft[ i ight] left[ j ight])表示(sleft[ i...j ight])中的括号取遍所有情况,该串的深度和。
    (s[i] eq '(')时,此时(s[i])(s[j])对答案没有任何贡献,那么(dp[i][j] += dp[i+1][j])
    (s[j] eq ')')时,此时(s[i])(s[j])对答案没有任何贡献,那么(dp[i][j] += dp[i][j-1])
    注意到如果(s[i] eq '(')(s[j] eq ')'),我们加上了两次(dp[i+1][j-1])的贡献,此时要(dp[i][j] -= dp[i+1][j-1])
    而如果(s[i] = ()(s[j] = ))或者其中有一个或两个是(?),即(s[i] eq ')')(s[j] eq '('),这个时候(s[i])(s[j])可以形成一对括号,对答案贡献了1,若区间([i+1,j-1])(k)个问号,则有(2^k)种情况,此时对答案贡献为(2^k),故(dp[i][j] += dp[i+1][j-1] + 2^k)
    综上,即:

    • (s[i] eq '(') , (dp[i][j] += dp[i+1][j])
    • (s[j] eq ')') , (dp[i][j] += dp[i][j-1])
    • (s[i] eq '(') && (s[j] eq ')') , (dp[i][j] -= dp[i+1][j-1])
    • (s[i] eq ')') && (s[j] eq '(') , (dp[i][j] += dp[i+1][j-1] + 2^k)

    区间DP。

    神奇的代码
    #include <bits/stdc++.h>
    #define MIN(a,b) ((((a)<(b)?(a):(b))))
    #define MAX(a,b) ((((a)>(b)?(a):(b))))
    #define ABS(a) ((((a)>0?(a):-(a))))
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        int s = 0, c = getchar();
        x = 0;
        while (isspace(c)) c = getchar();
        if (c == 45) s = 1, c = getchar();
        while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
        if (s) x = -x;
    }
    
    template <typename T>
    void write(T x, char c = ' ') {
        int b[40], l = 0;
        if (x < 0) putchar(45), x = -x;
        while (x > 0) b[l++] = x % 10, x /= 10;
        if (!l) putchar(48);
        while (l) putchar(b[--l] | 48);
        putchar(c);
    }
    
    const long long mo=998244353;
    
    const int N=2e3+8;
    
    char s[N];
    
    long long sum[N],dp[N][N];
    
    int len;
    
    void Input(void) {
        scanf("%s",s);
    }
    
    long long kuai(long long a,long long b){
        long long qwq=1;
        while(b){
            if (b&1) qwq=qwq*a%mo;
            a=a*a%mo;
            b>>=1;
        }
        return qwq;
    }
    
    void Solve(void) {
        len=strlen(s);
        sum[0]=(s[0]=='?');
        for(int i=1;i<len;++i) sum[i]=sum[i-1]+(s[i]=='?');
        for(int l=2;l<=len;++l)
            for(int j,i=0;i<len-l+1;++i){
                j=i+l-1;
                if (s[i]!='(') dp[i][j]=(dp[i][j]+dp[i+1][j])%mo;
                if (s[j]!=')') dp[i][j]=(dp[i][j]+dp[i][j-1])%mo;
                if (s[i]!='('&&s[j]!=')') dp[i][j]=(dp[i][j]-dp[i+1][j-1]+mo)%mo;
                if (s[i]!=')'&&s[j]!='(') dp[i][j]=((dp[i][j]+dp[i+1][j-1])%mo+kuai(2ll,sum[j-1]-sum[i]))%mo;
            }
    }
    
    void Output(void) {
        printf("%lld
    ",dp[0][len-1]);
    }
    
    main(void) {
        //int kase;
        freopen("input.txt", "r", stdin);
        freopen("output.txt", "w", stdout);
        //read(kase);
        //for (int i = 1; i <= kase; i++) {
            //printf("Case #%d: ", i);
            Input();
            Solve();
            Output();
        //}
    }
    


    这次的题都是贪心构造和期望和DPqwq。

  • 相关阅读:
    【Hibernate 5】继承映射配置及多态查询
    【Hibernate 4】一对多映射配置
    【Hibernate 3】一对一映射配置
    【ITOO 2】使用ArrayList时的注意事项:去除多余的null值
    ubuntu查看端口占用
    ubuntu安装LAMP环境
    @ResponseBody返回不能正确接收
    ubuntu apt常用命令
    ubuntu添加sudo权限
    ubuntu 13.10 skype登不上问题
  • 原文地址:https://www.cnblogs.com/Lanly/p/11995096.html
Copyright © 2011-2022 走看看