zoukankan      html  css  js  c++  java
  • bzoj4447[Scoi2015]小凸解密码

    4447: [Scoi2015]小凸解密码

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 150  Solved: 58
    [Submit][Status][Discuss]

    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-l
    数据保证合法,即数据中0≤pos<N,0≤num≤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 <=n,m≤10^5
     
     
     
    UPDATE:
    尴尬地发现其实方法有点小BUG,WA不是因为写错了。
     
    错误原因是这样的:
    如果区间端点为0,左右区间拼成环后构成新的跨越左右区间的0区间,这时候直接取$min(dis_l,dis_r)$ 不一定是答案,因为有可能左右区间的第二远的0区间比上面取min得到的答案更优,举一个例子:
    权值 0 0 0 0 0 1 1 1  0   0   0   1   0   0
    位置 1 2 3 4 5 6 8 9 10 11 12 13 14 15
    假设查询的是5位置,那么取min得到的答案就是0,而右边区间第二远的0区间的距离是4
     
    所以如果出现上述的区间端点为0的情况,就需要查询新的左右区间的最远0区间的距离,即删去跨越左右区间的0区间,再做一次查询最远0区间的操作。
    这样做以后虽然复杂度没变,但是常数扩大了很多,不知道能否过掉,有极大可能TLE 几组数据,所以代码就懒得改了
     
     
     
    发现了更好的办法
    做线段树的时候的时候可以直接维护维护离左右端点最远的和次远0区间的距离
     
    下面的blog就是这种做法,可以参照
    https://www.cnblogs.com/f321dd/p/6403097.html
     
     
     
    以下是原方法
     
     

    脑残的 二分+线段树

    化环成链,倍增区间

    查询的时候分成左右两段区间查询

    二分查询每个点最左边的0在哪个位置,最右边的0在哪个位置,用线段树check

    找到最左和最右的0之后,线段树查询当前0所在的区间的另一端点,距离为dis

    如果两区间不为查询点的端点都为0,那么查询到的最远的0都是端点了。

    说明左右区间拼成环之后,可以构成一个新的跨越了左右区间的0区间,答案取$min{(dis_l,dis_r)}$  否则取$max{(dis_l,dis_r)}$

    WA + TLE
    WA估计是写的时候出了点小错误,不想调试啦。
    TLE这东西加点常数优化应该是可以卡过的
    好像还有set作法貌似挺简单,直接存全为0的区间即可

      1 #include<bits/stdc++.h>
      2 #define ls u<<1
      3 #define rs ls|1
      4 #define N 200010
      5 using namespace std;
      6 int n,m,a[N],b[N],pd[N<<2],lz[N<<2],lx[N<<2],rx[N<<2];char s[N];
      7 void pushup(int u,int l,int r){
      8     int mid=(l+r)>>1;
      9     pd[u]=pd[ls]|pd[rs];
     10     lx[u]=lx[ls];rx[u]=rx[rs];
     11     if(lx[u]==mid-l+1)lx[u]+=lx[rs];
     12     if(rx[u]==r-mid)rx[u]+=rx[ls];
     13 }
     14 void build(int u,int l,int r){
     15     if(l==r){
     16         if(!b[l])pd[u]=lx[u]=rx[u]=1;
     17         else pd[u]=lx[u]=rx[u]=0;
     18         return;
     19     }
     20     int mid=(l+r)>>1;
     21     build(ls,l,mid);
     22     build(rs,mid+1,r);
     23     pushup(u,l,r);
     24 }
     25 void update(int u,int l,int r,int p){
     26     if(l==r){
     27         if(!b[l])pd[u]=lx[u]=rx[u]=1;
     28         else pd[u]=lx[u]=rx[u]=0;
     29         return;
     30     }
     31     int mid=(l+r)>>1;
     32     if(p<=mid)update(ls,l,mid,p);
     33     else update(rs,mid+1,r,p);
     34     pushup(u,l,r);
     35 }
     36 
     37 int query(int u,int L,int R,int l,int r){
     38     if(l<=L&&R<=r)return pd[u];
     39     int mid=(L+R)>>1,ret=0;
     40     if(l<=mid)ret|=query(ls,L,mid,l,r);
     41     if(r>mid)ret|=query(rs,mid+1,R,l,r);
     42     return ret;
     43 }
     44 int asklx(int u,int L,int R,int l,int r){
     45     if(l==L&&R==r)return lx[u];
     46     int mid=(L+R)>>1,ret=0;
     47     if(r<=mid)return asklx(ls,L,mid,l,r);
     48     if(l>mid)return asklx(rs,mid+1,R,l,r);
     49     ret+=asklx(ls,L,mid,l,mid);
     50     if(!ret)return 0;
     51     if(ret==mid-l+1)ret+=asklx(rs,mid+1,R,mid+1,r);
     52     return ret;
     53 }
     54 int askrx(int u,int L,int R,int l,int r){
     55     if(l==L&&R==r)return rx[u];
     56     int mid=(L+R)>>1,ret=0;
     57     if(r<=mid)return askrx(ls,L,mid,l,r);
     58     if(l>mid)return askrx(rs,mid+1,R,l,r);
     59     ret+=askrx(rs,mid+1,R,mid+1,r);
     60     if(!ret)return 0;
     61     if(ret==r-mid)ret+=askrx(ls,L,mid,l,mid);
     62     return ret;
     63 }
     64 inline int solve(int x){
     65     static int t1,t2,x1,x2,L,R,l,r;
     66     int mid=(1+n)>>1;
     67     if(x<mid)x+=n;
     68     L=x-mid+1;R=x+mid;
     69     if(!((1+n)&1))R--;
     70     t1=t2=0;
     71     l=x,r=R;
     72     while(l<=r){
     73         mid=(l+r)>>1;
     74         if(query(1,1,n<<1,mid,R))t2=mid,l=mid+1;
     75         else r=mid-1;
     76     }
     77     l=L,r=x;
     78     while(l<=r){
     79         mid=(l+r)>>1;
     80         if(query(1,1,n<<1,L,mid))t1=mid,r=mid-1;
     81         else l=mid+1;
     82     }
     83     if(!t1&&!t2)return -1;
     84     if(t1==x&&t2==x)return 0;
     85     x1=t1+asklx(1,1,n<<1,t1,x)-1;
     86     x2=t2-askrx(1,1,n<<1,x,t2)+1;
     87     if(x1==x&&x2==x)return 0;
     88     if(t1==L&&t2==R)return min(x2-x,x-x1);
     89     return max(x2-x,x-x1);
     90 }
     91 inline void change(int p,int op){
     92     static int k;k=p-1;if(!k)k=n;
     93     if(op)b[p]=(a[k]+a[p])%10;
     94     else b[p]=1ll*a[k]*a[p]%10;
     95     if(p>n)b[p-n]=b[p];
     96     else b[p+n]=b[p];
     97 }
     98 int main(){
     99     scanf("%d%d",&n,&m);
    100     for(int i=1;i<=n;i++)
    101     scanf("%d %c",&a[i],&s[i]);
    102     for(int i=1;i<=n;i++){
    103         int j=i-1;if(!j)j=n;
    104         if(s[i]=='+')b[i]=(a[i]+a[j])%10;
    105         else b[i]=1ll*a[i]*a[j]%10;
    106         b[i+n]=b[i];s[i+n]=s[i];a[i+n]=a[i];
    107     }
    108     build(1,1,n<<1);
    109     int x,y,z,p;char op;
    110     while(m--){
    111         scanf("%d%d",&x,&y);++y;
    112         if(x==1){
    113             scanf("%d %c",&z,&op);
    114             a[y]=a[y+n]=z;s[y]=s[y+n]=op;
    115             change(y,s[y]=='+'?1:0);
    116             update(1,1,n<<1,y);
    117             update(1,1,n<<1,y+n);
    118             change(y+1,s[y+1]=='+'?1:0);
    119             update(1,1,n<<1,y+1);
    120             p=y+1>n?y+1-n:y+1+n;
    121             update(1,1,n<<1,p);
    122         }
    123         else printf("%d
    ",solve(y));
    124     }
    125     return 0;
    126 }

     

  • 相关阅读:
    Python max() 函数
    Python log10() 函数
    Python log() 函数
    Python fabs() 函数
    Java开源-astar:A 星算法
    9款超绚丽的HTML5/CSS3应用和动画特效
    Java中处理异常的9个最佳实践
    Java泛型
    Android界面性能调优手册
    正确使用Android性能分析工具——TraceView
  • 原文地址:https://www.cnblogs.com/wsy01/p/8324760.html
Copyright © 2011-2022 走看看