【CodeForces】947 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; }