4447: [Scoi2015]小凸解密码
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 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
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
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 }