不得不表示,能用栈来做的题目前对我来说都很费解,这题又是抄的,来自校友JMDWQ,只不过把C改成了C++。开始时我用的是暴搜,数组的每一位就是一个“魂器”,而他的栈结构里每一位是连续相同的“魂器”的长度,明显要好的多。对他的核心代码,我的理解是这样的,大牛勿喷:
判断当前与前一位 相同:栈顶++;(当前连续区长度+1)
不同:不能变化 || top==0: s[++top] = 1;(开辟新区,长度为1)
能变化 && top(存在区):只有一个区:栈顶++(长度+1);t = !t(最左边的区变了);
存在多个区:s[top-1] += s[top]+1;top--;(合并区);
现在举一个最后一种情况的例子:00110001,当前到最后一个,“1”,不同,可以变化,之前有三个区,s[1]==2,s[2]==2,s[3]==3,区3里的3个0都变为1,加上的当前的1(可以理解为区4),全都合并的区2里了,s[2] += s[3]+1;top--就是少一个区嘛。
最后不得不说代码中t的安排,真是巧妙。所有的区是0、1、0、1间隔的,t变化表示最左边的区变了,后来的top%2==t是用来判断当前也就是最后一个区是0还是1;本来我还是搞不清,后来看到t=f(第一个数),我觉悟了,原来t 一开始就是最左边的,它是0 t也是0,它是1 t也是1;然后它变t也变,完全一样嘛!t与top各2种情况,一共4种,枚举一下就发现这样会保证top指向0,真是妙,以后我也这样判断。
1 #include<iostream> 2 using namespace std; 3 const int MAXN = 100010; 4 unsigned short s[MAXN]; 5 int main() 6 { 7 int t,f,top,ans,i,n,x; 8 while(cin>>n) 9 { 10 top = ans = 0; 11 memset(s,0,sizeof(s)); 12 cin>>f; 13 t = f; 14 s[++top] = 1; 15 for(i = 1; i < n; i++) 16 { 17 cin>>x; 18 if(f!=x) 19 { 20 f = x; 21 if(i%2 && top) 22 if(top > 1) 23 s[top-1] += s[top]+1,top--; 24 else 25 s[top]++,t = !t; 26 else s[++top] = 1; 27 } 28 else s[top]++; 29 } 30 if(top%2 == t) top--; 31 while(top > 0) 32 { 33 ans += s[top]; 34 top -= 2; 35 } 36 cout<<ans<<endl; 37 } 38 return 0; 39 }