• [bzoj4447] [loj#2010] [Scoi2015] 小凸解密码


    Description

    小凸得到了一个密码盘,密码盘被等分成 (N) 个扇形,每个扇形上有一个数字(0~9),和一个符号(“+”或"*")
    密码盘解密的方法如下:
    首先,选择一个位置开始,顺时针地将数字和符号分别记在数组 (A) 和数组 (C)
    解密的方法如下
    (B0=A0)
    (x>0) 时:
    (Cx) 为“+”,(Bx=(Ax+Ax-1) \%10) ,注意:(x-1) 是下标值
    (Cx) 为“*”,(Bx= (Ax×Ax-1) \%10) ,注意:(x-1) 是下标值
    操作完成后,可以得到一个长度为 (n) 的数组 (B) ,然后以 (B0) 为起点将 (B) 数组顺时针写成一个环,解密就完成了,称得到的环为答案环。

    现在小凸得到了一份指令表,指令表上有2种操作。
    一种指令是修改操作,即改变原来密码盘上一个位置的数字和符号。
    另一种指令是询问操作,具体如下:
    首先从指令给出的位置开始完成解密,得到答案环。
    答案环上会有一些 (0) 连在一起,将这些连在一起的 (0) 称为零区间,找出其中距离 (B0) 最远的那个零区间,输出这个距离。
    零区问和 (B0) 的距离定义为:零区问内所有 (0)(B0) 距离中的最小值。

    Input

    第 1 行包含2个整数 (n) , (m) ,代表密码盘大小和指令个数
    接下来 (n) 行,每行包含1个整数和1个字符,按顺时针顺序给出了密码盘上的数组和符号
    接下来 (m) 行,依次给出指令
    每行第1个整数代表指令类型
    若第1个整数为1,代表本行对应指令为修改操作,之后依次有2个整数 (pos)(num) 和1个字符 (opt) ,分别代表修改的位置,以及修改后该位置的数字和字符
    若第1个整数为2,代表本行对应指令位询问操作,之后有1个整数 (pos) ,代表本次操作中解密的开始位置
    密码盘上的位置标号为 (0)(n-1)
    数据保证合法,即数据中 (0 leq pos < N)(0 leq num leq 9)(opt) 为“+”或“*”

    Output

    对于每个询问操作1行,输出答案,若答案环上没有0,输出-1

    Sample Input

    5 8

    0 *

    0 *

    0 *

    0 *

    0 *

    2 0

    1 0 1 +

    1 2 1 +

    2 3

    1 1 1 +

    1 3 1 +

    1 4 1 +

    2 4

    Sample Output

    0

    2

    -1

    HINT

    第1个询问,答案环为[0,0,0,0,0],仅有1个零区间,且 (B0) 在其中,所以距离是0

    对于第2个询问,答案环为[0,0,1,0,l],有2个零区间,(0,1)和 (B0) 距离是o,(3,3)和 (B0) 距离是2,故答案为2

    对于第3个询问,答案环为[1,2,2,2,2],没有零区间,答案是-1

    对于 (100 \%) 数据,(5 leq n,m leq 10^5)


    想法

    修改看起来可以很快,那先搞查询。
    拆环为链,线段树维护 (B) 数组
    要求距离最远的0区间,我感觉距离又最大又最小很麻烦,就二分吧
    二分 (mid) 后对应了环上的一段区间 ([pos+mid,pos+n-mid]),分情况讨论:
    1.区间内包含完整的0区间:那个完整的0区间到 (B0) 的距离肯定比 (mid) 大,所以 (l=mid+1)
    2.区间内不含完整的0区间,但区间内有0(即0在区间边缘):那么最终答案肯定不会比 (mid) 大,所以 (r=mid)
    3.区间内没有0:答案肯定小于 (mid) ,所以 (r=mid-1)
    线段树维护区间有没有完整的0区间及左右端点连续的0的个数,随便搞一搞(可不行……细节不少……)
    剩下的随便 (yy) 一下,总复杂度 (O(nlog^2n)) 简单粗暴。

    网上有用 (set) 维护0区间端点的 (O(nlogn)) 做法,不过我还是觉得线段树友好【逃】


    代码

    必须承认,细节很多。。。
    但是 (1A) 了可喜可贺!

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
     
    using namespace std;
     
    int read(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch) && ch!='-') ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
     
    const int N = 200005;
     
    int n,m;
    int a[N],c[N],b[N];
     
    int root,cnt,ch[N*2][2];
    struct fea{ int full,lm,rm; }d[N*2];
    fea merge(fea ls,int lenl,fea rs,int lenr){
        fea x;
        x.full=max(ls.full,rs.full);
        if(ls.rm+rs.lm>0 && ls.rm!=lenl && rs.lm!=lenr) x.full=1;
        x.lm= (ls.lm==lenl ? ls.lm+rs.lm : ls.lm);
        x.rm= (rs.rm==lenr ? rs.rm+ls.rm : rs.rm);
        return x;
    }
    void build(int x,int l,int r){
        if(l==r){
            if(b[l]==0) d[x]=(fea){0,1,1};
            else d[x]=(fea){0,0,0};
            return;
        }
        int mid=(l+r)>>1;
        build(ch[x][0]=++cnt,l,mid);
        build(ch[x][1]=++cnt,mid+1,r);
        d[x]=merge(d[ch[x][0]],mid-l+1,d[ch[x][1]],r-mid);
    }
    void change(int x,int l,int r,int pos,int num){
        if(l==r){
            if(num==0) d[x]=(fea){0,1,1};
            else d[x]=(fea){0,0,0};
            return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid) change(ch[x][0],l,mid,pos,num);
        else change(ch[x][1],mid+1,r,pos,num);
        d[x]=merge(d[ch[x][0]],mid-l+1,d[ch[x][1]],r-mid);
    }
    fea ask(int x,int l,int r,int L,int R){
        if(l==L && r==R) return d[x];
        int mid=(l+r)>>1;
        if(R<=mid) return ask(ch[x][0],l,mid,L,R);
        else if(L>mid) return ask(ch[x][1],mid+1,r,L,R);
        return merge(ask(ch[x][0],l,mid,L,mid),mid-L+1,ask(ch[x][1],mid+1,r,mid+1,R),R-mid);
    }
     
    int main()
    {
        char chh[2];
        n=read(); m=read();
        for(int i=1;i<=n;i++){
            a[i]=read();
            scanf("%s",chh);
            if(chh[0]=='+') c[i]=1;
            else c[i]=2;
        }
         
        a[0]=a[n];
        for(int i=1;i<=n;i++){
            if(c[i]==1) b[i]=(a[i]+a[i-1])%10;
            else b[i]=(a[i]*a[i-1])%10;
            b[i+n]=b[i];
        }
        build(root=++cnt,1,n*2);
         
        int pos,opt;
        while(m--){
            opt=read();
            if(opt==1){
                pos=read()+1; a[pos]=read();
                scanf("%s",chh);
                c[pos]= (chh[0]=='+' ? 1 : 2 );
                if(c[pos]==1) b[pos]=(a[pos]+a[pos-1])%10;
                else b[pos]=(a[pos]*a[pos-1])%10;
                b[pos+n]=b[pos];
                change(root,1,n*2,pos,b[pos]);
                change(root,1,n*2,pos+n,b[pos+n]);
                 
                if(pos==n) { a[0]=a[pos]; pos=1; }
                else pos++;
                if(c[pos]==1) b[pos]=(a[pos]+a[pos-1])%10;
                else b[pos]=(a[pos]*a[pos-1])%10;
                b[pos+n]=b[pos];
                change(root,1,n*2,pos,b[pos]);
                change(root,1,n*2,pos+n,b[pos+n]);
            }
            else{
                pos=read()+1;
                change(root,1,n*2,pos,a[pos]); change(root,1,n*2,pos+n,a[pos]);
                int l=0,r=n/2,mid;
                while(l<r){
                    mid=(l+r)>>1;
                    fea x=ask(root,1,n*2,pos+mid,pos+n-mid);
                    if(x.full) l=mid+1;
                    else if(x.lm || x.rm) r=mid;
                    else r=mid-1;
                }
                if(l==0){
                    fea x=ask(root,1,n*2,pos,pos+n);
                    if(!x.full && !x.lm && !x.rm) printf("-1
    ");
                    else printf("0
    ");
                }
                else printf("%d
    ",l);
                change(root,1,n*2,pos,b[pos]); change(root,1,n*2,pos+n,b[pos]);
            }
        }
         
        return 0;
    }
    
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    [2020.12.5周六]Boruvka
    [2020.12.4周五] 圆上对称博弈
    [2020.12.3周四]最长上升子序列
    置顶~ 未来半年内训练计划
    cf1473d
    cf1474D
    寒假复健第一天 cf1475D
    来啦来啦,寒假复健第一题cf1475g
    12.1加训总结 2019南京
    12.7-12.13训练计划
  • 原文地址:https://www.cnblogs.com/lindalee/p/11402935.html
Copyright © 2020-2023  润新知