名校聯賽第三天A層 問題 C: 與非題解
問題 C: 與非
時間限制: 2 Sec 內存限制: 256 MB題目描述
作為一名新世紀共產主義的接班人,你認識到了資本主義的軟弱性與妥協性,決定全面根除資本主義,跑步邁入共產主義。但是當你即將跨入共產主義大門的時候,遇到了萬惡的資本家留下的與非電路封印,經過千辛萬苦的研究,你終於把復雜的破解轉變成了以下問題:
初始時你有一個空序列,之後有N個操作。
操作分為一下兩種:
1 x:在序列末尾插入一個元素x(x=0或1)。
2 L R:定義nand[L,R]為序列第L個元素到第R個元素的與非和,詢問nand[L,L]^nand[L,L+1]^nand[L,L+2]^......^nand[L,R]。
Nand就是先與,再非
輸入
從文件nand.in中讀入數據。
輸入第一行一個正整數N,表示操作個數。
接下來N行表示N個操作。
為了體現程序的在線性,記lastans為上一次操作二的回答,初始lastans=0,。對於操作1,你需要對x異或lastans。對於操作二,設現在序列中的元素個數為M,如果lastans=1,那麽你需要作如下操作:L=M-L+1,R=M-R+1,swap(L,R)
輸出
輸出到nand.out中。
輸出有多行。為對於每一個操作二的回答。
樣例輸入
6 1 1 1 1 1 0 2 1 2 2 1 3 2 2 3
樣例輸出
1 0 0
提示
【數據規模和約定】
N<=4000000 M1<=3900000 M2<=100000
先吐槽一下題目描述,上面的題目是我自己矯正過的,原來題目就卡死了無數人,連樣例都搞不出來。
這道題先膜拜一下Troywar大犇,成功通過理性分析與令人窒息的操作強行幹過這道題,成功蔑視了數據和出題人的智商。因此我今天就講一下擼串神的比正解快出去無數倍的“非正解”。
首先,先設定f[i]為nand[1,i],所以f[i]的通項公式就明了了f[i+1]=!(f[i]&a[i+1]),nand[i,i+1]=!(a[i]&a[i+1]),nand[i+2]=!(nand[i+1]&a[i+2]),que[i,j]=a[i]^nand[i+1]^nand[i+2]……
那我們先觀察一下f[i+1]和nand[i,i+1],可以發現,若a[i+1]=0那麽兩式相等,使nand[i+2]=f[i+2],以此類推,可以發現只要有零出現,後方的f[i]一定等於nand[i],一次對於每一次訊問我們只要先暴力找一下第一個為零或直接找f[i]與nand[i]相等的地方就可以,後面f[i]與nand[i]都相等了,因此只要再去維護一個前綴f[i]的異或和即可,找到0後直接將數據分開處理,在0左方直接暴力,在0右方(包括0位),用前綴和搞。
可能很多人會有疑惑,這樣不會超時嗎,當然不會,首先,通過本題的題目描述可以推斷,他一定不是先添加完再詢問,應當是添加完一點再去詢問幾次,這樣,由於他的強制在線,出現0的幾率是相當大的,因此不會超時,實在擔心的話也可以記錄一下0的出現次數的前綴和,然後再去二分查找。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<map> 7 #include<queue> 8 #include<string> 9 #include<cmath> 10 using namespace std; 11 int n,la,zz; 12 int a[4000005]; 13 int f[4000005]; 14 int sum[4000005]; 15 int nand(int x,int y){ 16 return (!(x&y)); 17 } 18 int na[50]; 19 int su[4000005][2]; 20 int main(){ 21 // freopen("nand.in","r",stdin); 22 // freopen("nand.out","w",stdout); 23 scanf("%d",&n); 24 for(int i=1;i<=n;i++) 25 { 26 int z; 27 scanf("%d",&z); 28 if(z==1) 29 { 30 int x; 31 scanf("%d",&x); 32 x^=la; 33 zz++; 34 a[zz]=x; 35 36 f[zz]=nand(f[zz-1],a[zz]); 37 sum[zz]=sum[zz-1]^f[zz]; 38 39 su[zz][0]=su[zz-1][0]; 40 su[zz][1]=su[zz-1][1]; 41 42 su[zz][x]++; 43 } 44 else 45 { 46 int x,y; 47 scanf("%d%d",&x,&y); 48 if(la) 49 { 50 x=zz-x+1; 51 y=zz-y+1; 52 swap(x,y); 53 } 54 int cnt=a[x],bj=0,sm=a[x]; 55 for(int i=x+1;i<=y;i++) 56 { 57 sm=nand(sm,a[i]); 58 if(sm==f[i]) 59 { 60 bj=i; 61 break; 62 } 63 cnt^=sm; 64 } 65 if(bj) cnt^=sum[y]^sum[bj-1]; 66 la=cnt; 67 printf("%d\n",la); 68 } 69 } 70 // while(1); 71 return 0; 72 }View Code
名校聯賽第三天A層 問題 C: 與非題解