• 【CodeForces】947 D. Picking Strings


    【题目】D. Picking Strings

    【题意】给定只含'A','B','C'的字符串,支持以下变换:1.A - BC   2.B - AC   3.C - AB   4.AAA - empty string(左边变成右边)

    给定S串和T串,q次询问,每次给出S串的一个子串x和T串的一个子串y,求x是否能变到y。n,m,q<=10^5。

    【算法】模拟???

    【题解】观察一些规律,首先B和C等价:B-AC-AAB-AAAC-C。

    然后B前面的A可以消除:AB-AAC-AAAB-B。

    所以新的变换:1.A - BB   2.B - AB   3.AB - B   4.AAA - empty string

    总结出以下规律:

    1.B前可以增减A。

    2.在已有B的基础上,B的数量增加任意偶数。

    依靠以上两点,我们就只剩下末尾A的问题:末尾A无法制造,所以策略是保留和目标串末尾数量相同的A,然后剩余的变化最后一个A或%3消除。下面假设从S变到T

    1.如果[T串的B少] 或 [两串B的奇偶性不同] 或 [T串的末尾A多],无解。

    删除末尾相当数量的A后:

    2.决定变化最后一个A,若满足[T串的B较多] 和 [S串还有A],有解。

    3.决定%3消除,除了%3=0还需要满足[不存在 S串无B而T串有B ]的情况,有解。(这是因为没有B时B不能凭空出现,就必须变化最后一个A)

    4.否则,无解。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=100010;
    int n,m,sa[maxn],sb[maxn],ta[maxn],tb[maxn];
    char s[maxn],t[maxn];
    int main(){
        scanf("%s%s",s+1,t+1);
        n=strlen(s+1);m=strlen(t+1);
        for(int i=1;i<=n;i++){
            if(s[i]=='A')sa[i]=sa[i-1]+1;
            sb[i]=sb[i-1]+(s[i]=='B'||s[i]=='C');
        }
        for(int i=1;i<=m;i++){
            if(t[i]=='A')ta[i]=ta[i-1]+1;
            tb[i]=tb[i-1]+(t[i]=='B'||t[i]=='C');
        }
        int Q;
        scanf("%d",&Q);
        while(Q--){
            int l,r,Sa,Sb,Ta,Tb;
            scanf("%d%d",&l,&r);
            Sa=min(r-l+1,sa[r]);Sb=sb[r]-sb[l-1];//
            scanf("%d%d",&l,&r);
            Ta=min(r-l+1,ta[r]);Tb=tb[r]-tb[l-1];
            if(Tb<Sb||((Tb&1)!=(Sb&1))||Ta>Sa)printf("0");else
            if((Ta<Sa&&Tb>Sb)||(!(Tb>0&&!Sb)&&(Sa-Ta)%3==0))printf("1");else
            printf("0");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    IBM Minus One(water)
    约瑟夫问题的循环链表实现
    双向链表(差不多)
    单向链表的建立,插入,删除(复习一下)
    找新朋友(欧拉函数)
    验证角谷猜想(hd1279)
    Wolf and Rabbit(gcd)
    Big Number(大数)
    字串数(高精度组合数)
    寻找素数对(hd1262)
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8545415.html
Copyright © 2020-2023  润新知