Sereja and Algorithm -----Codeforces Round #215 div.1 A

解析 CodeForces 367A 题目,介绍一种利用区间树解决字符串合法性的方法。通过统计子串中字符 x、y、z 的出现次数来判断其是否符合特定条件。

http://codeforces.com/contest/367/problem/A


题意:

给你一个字符串,你在其中找包含3个字符的连续的子串,再以任意顺序放回去,如果你不管放回多少次,每次都能找出不是“zyx” “yxz" "xzy"的这3种,那么这个字符串就是不合格的。

现在是给你一个字符串,m个询问,每个询问问你字符串从a位置到b位置的子串是不是合格的,合格的输出YES,不合格输出NO。

分析:

1.  如果你选出的字符串不足3个字符,那么你第一次就不能找出非上面的3种字符串(虽然上面的3种也不能找出),那么该字符串肯定是合格的。

2.  当选出的字符串大于3个字符时,首先犹豫是以任意的顺序放回去,那么该字符串的起始排列其实是没有任何价值的,唯一有价值的就是x,y,z分别的个数。

     首先是x:y:z=1:1:1的时候,那么肯定是合格的,怎么才是不合格的呢?因为可以循环使用例如zyxz,这个字符串也是合格的,所以当其中一个比另外两个较少的那一个还多2个的话,那么这个串就是不合格的,否则就一定合格。

#include <cstdlib>
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define inf 2147480000
struct hammer
{
   int right,left;
   int x;
   int y;
   int z;
}box[400401];
string s;
int sumx,sumy,sumz;
void build(int now,int l,int r)
{
     box[now].left=l;box[now].right=r;
     if(r==l)
     {
        if(s[l-1]=='x')
        {
            box[now].x=1;box[now].y=box[now].z=0;
        }
        else if(s[l-1]=='y')
        {
            box[now].y=1;box[now].x=box[now].z=0;
        }
        else if(s[l-1]=='z')
        {
            box[now].z=1;box[now].x=box[now].y=0;
        }
     }
     else
     {
       int k=(r+l)/2;
       build(now*2,l,k);
       build(now*2+1,k+1,r);
       box[now].x=box[now*2].x+box[now*2+1].x;
       box[now].y=box[now*2].y+box[now*2+1].y;
       box[now].z=box[now*2].z+box[now*2+1].z;
     }

}
void qury(int a,int l,int r)
{
    if(box[a].left==l && box[a].right==r)
    {
        sumx+=box[a].x;
        sumy+=box[a].y;
        sumz+=box[a].z;
    }
    else
    {
        int k=(box[a].right+box[a].left)/2;
        if(k<l)
        {
           qury(a*2+1,l,r);
        }
        else if(k>=r)
        {
           qury(a*2,l,r);
        }
        else
        {
           qury(a*2,l,k);
           qury(a*2+1,k+1,r);
        }
    }
}
int m;
int main(int argc, char *argv[])
{
    cin>>s;
    cin>>m;
    build(1,1,s.size());
    for(int i=1;i<=m;i++)
    {
        sumx=0;sumy=0;sumz=0;
        int a,b;
        scanf("%d%d",&a,&b);
        if(b-a+1<3) cout<<"YES"<<endl;
        else
        {
            qury(1,a,b);
            int minn=inf;
            minn=min(minn,sumx);
            minn=min(minn,sumy);
            minn=min(minn,sumz);
            sumx-=minn;
            sumy-=minn;
            sumz-=minn;
            if(sumx>=2 || sumy>=2 || sumz>=2)
            {
                cout<<"NO"<<endl;
            }
            else
            {
                cout<<"YES"<<endl;
            }
        }

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值