不得不表示,能用栈来做的题目前对我来说都很费解,这题又是抄的,来自校友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 }