Kefa and Watch CodeForces - 580E

http://codeforces.com/problemset/problem/580/E

两种操作 一是将区间全部改为某个数字 二是询问一个区间内的数字串是否具有周期性

大体思路是 线段树维护区间哈希值 设周期为t 先查[l,l+t-1] [l+t,l+3t-1] [l+3t,l+7t-1]...这些段 看两个上一段拼起来是否等于当前段   再用同意方法反过来查右边 两边肯定在中间会合 单词查询复杂度logn*logn 但是会有特殊情况就是左右两边正好“相切” 需要再查一下最左边和最右边的一个周期长度的区间值是否相等 如果区间长度不是t的整数倍 就特判一下余数

这个题卡ull 得用大素数 以后记住再也不用ull了。。

 

去年做到的这套题 当时就想 这e题说的什么玩意 是人做的吗 现在再看已经很快就能有思路 并且还能写出来 虽然花了差不多一上午 但起码说明自己还是有点长进的吧     要退役了发点牢骚。。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+10;

ll pre[10][maxn],decm[maxn];
ll lef[4*maxn],rgt[4*maxn];
int laz[4*maxn];
int n,m,k,q;
char ch[maxn];

void init()
{
    ll i,j,t;
    t=255;
    for(i=0;i<10;i++){
        for(j=1;j<=100000;j++) pre[i][j]=((t*pre[i][j-1])%mod+i+'0')%mod;
    }
    decm[0]=1;
    for(i=1;i<=100000;i++) decm[i]=(t*decm[i-1])%mod;
}

void change(int val,int len,int cur)
{
    lef[cur]=rgt[cur]=pre[val][len];
    laz[cur]=val;
}

void pushup(int l,int r,int cur)
{
    int m;
    m=(l+r)/2;
    lef[cur]=(lef[2*cur]+(lef[2*cur+1]*decm[m-l+1])%mod)%mod;
    rgt[cur]=((rgt[2*cur]*decm[r-m])%mod+rgt[2*cur+1])%mod;
}

void pushdown(int l,int r,int cur)
{
    int m;
    if(laz[cur]!=-1){
        m=(l+r)/2;
        change(laz[cur],m-l+1,2*cur);
        change(laz[cur],r-m,2*cur+1);
        laz[cur]=-1;
    }
}

void build(int l,int r,int cur)
{
    int m;
    laz[cur]=-1;
    if(l==r){
        lef[cur]=rgt[cur]=ch[l-1];
        return;
    }
    m=(l+r)/2;
    build(l,m,2*cur);
    build(m+1,r,2*cur+1);
    pushup(l,r,cur);
}

void update(int pl,int pr,int val,int l,int r,int cur)
{
    int m;
    if(pl<=l&&r<=pr){
        change(val,r-l+1,cur);
        return;
    }
    pushdown(l,r,cur);
    m=(l+r)/2;
    if(pl<=m) update(pl,pr,val,l,m,2*cur);
    if(pr>m) update(pl,pr,val,m+1,r,2*cur+1);
    pushup(l,r,cur);
}

ll query(int tp,int pl,int pr,int l,int r,int cur)
{
    ll res1,res2,res;
    int m;
    if(pl<=l&&r<=pr){
        if(tp==0) return lef[cur];
        else return rgt[cur];
    }
    pushdown(l,r,cur);
    m=(l+r)/2;
    if(pl<=m) res1=query(tp,pl,pr,l,m,2*cur);
    else res1=0;
    if(pr>m) res2=query(tp,pl,pr,m+1,r,2*cur+1);
    else res2=0;
    if(tp==0) res=(res1+(res2*decm[max(0,m-max(l,pl)+1)])%mod)%mod;
    else res=((res1*decm[max(0,min(r,pr)-m)])%mod+res2)%mod;
    return res;
}

int main()
{
    ll gou,res;
    int i,op,pl,pr,l,r,val,len,f0,f1,f2,f3;
    init();
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s",ch);
    q=m+k;
    build(1,n,1);
    while(q--){
        scanf("%d%d%d%d",&op,&pl,&pr,&val);
        if(op==1) update(pl,pr,val,1,n,1);
        else{
            l=pl,r=pr-(pr-pl+1)%val;

            gou=query(0,l,l+val-1,1,n,1);
            i=l+val,len=2*val,f0=1;
            while(i+len-1<=r){
                gou=((gou*decm[len/2])%mod+gou)%mod;
                res=query(0,i,i+len-1,1,n,1);
                if(res!=gou){
                    f0=0;
                    break;
                }
                i+=len,len*=2;
            }

            gou=query(1,r-val+1,r,1,n,1);
            i=r-val,len=2*val,f1=1;
            while(i-len+1>=l){
                gou=((gou*decm[len/2])%mod+gou)%mod;
                res=query(1,i-len+1,i,1,n,1);
                if(res!=gou){
                    f1=0;
                    break;
                }
                i-=len,len*=2;
            }
            if(query(1,l,l+val-1,1,n,1)==query(1,r-val+1,r,1,n,1)) f2=1;
            else f2=0;

            if(f0&&f1&&f2){
                if((pr-pl+1)%val){
                    if(query(0,l,l+(pr-pl+1)%val-1,1,n,1)==query(0,r+1,r+(pr-pl+1)%val,1,n,1)) f3=1;
                    else f3=0;
                }
                else f3=1;
                if(f3) printf("YES\n");
                else printf("NO\n");
            }
            else printf("NO\n");
        }
    }

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值