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
 
 
 
如下是原方法
 
 

腦殘的 二分+線段樹php

化環成鏈,倍增區間html

查詢的時候分紅左右兩段區間查詢c++

二分查詢每一個點最左邊的0在哪一個位置,最右邊的0在哪一個位置,用線段樹check數組

找到最左和最右的0以後,線段樹查詢當前0所在的區間的另外一端點,距離爲dis優化

若是兩區間不爲查詢點的端點都爲0,那麼查詢到的最遠的0都是端點了。ui

說明左右區間拼成環以後,能夠構成一個新的跨越了左右區間的0區間,答案取$min{(dis_l,dis_r)}$  不然取$max{(dis_l,dis_r)}$spa

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 }
相關文章
相關標籤/搜索