妈蛋,开始都没看懂题意,临近结束了才知道题意,只知道是dp。
但是还是没得发现子结构是什么。。
具体思路:
先统计从0到i(截止点是i)的奇数区间和偶数区间。
这个我也不会。。
然后在排除状如 0001 和10000的情况
你会发现,一个0可以会增加一个非法区间,一个1本身就是非法区间。。
所以我第一个初始就调成1,顺带记录1的个数了。。
改成longlong。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
/*昨天写这一道题写失败了。。没有弄清意思,
这种 类似维护出 一个 dp
*/
const int maxn=200007;
int main()
{ int m;
long long dp[maxn][2];
char a[maxn];
scanf("%d",&m);
while(m--)
{ int len;
memset(dp,0,sizeof(dp));
memset(a,0,sizeof(a));
scanf("%d",&len);
getchar();
for(int i=0;i<len;i++)
scanf("%c",&a[i]);
if(a[0]=='1')
{ dp[0][0]=1;//0设置为奇数区间的个数
dp[0][1]=0;
}
else
{ dp[0][0]=0;
dp[0][1]=1;// 0 构成一个偶数区间.
}
for(int i=1;i<len;i++)
{ if(a[i]=='1')//奇数区间遇1则变。偶数区间不变。
{ dp[i][0]=dp[i-1][1]+1;
dp[i][1]=dp[i-1][0];//偶数区间为以前的奇数区间
}
else
{ dp[i][0]=dp[i-1][0];
dp[i][1]=dp[i-1][1]+1;
}
}
/*for(int i=0;i<len;i++)
{ cout<<"奇数区间"<<endl;
printf("%d ",dp[i][0]);
}
cout<<endl;
for(int i=0;i<len;i++)
{ cout<<"偶数区间"<<endl;
printf("%d ",dp[i][1]);
}*/
long long sum=0;
for(int i=0;i<len;i++)
sum+=dp[i][0];
long long res=1;
long long all=0;
for(int i=0;i<len;i++)//这个事删除001 之流。发现每增加一个0,贡献一个非法区间
{ if(a[i]=='1')
{ all+=res;
res=1;//为啥这个初始化为1呢,因为一个1也贡献一个非法的
}
else
res++;
}
res=0;
for(int i=len-1;i>=0;i--)//去掉 100之流。
{ if(a[i]=='1')
{ all+=res;
res=0;
}
else res++;
}
printf("%lld\n",sum-all);
}
return 0;
}