【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

 

posted @ 2018-03-11 19:31  ONION_CYC  阅读(305)  评论(0编辑  收藏  举报