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\n",solve(y));
124     }
125     return 0;
126 }

 

 

posted @ 2018-01-21 17:01  _wsy  阅读(542)  评论(1编辑  收藏  举报