规律:如果从1开始往右走的话,如果从(1~i)经过的零的个数和有奇数个零的话(那么i与下个数必定要有一个来回),可以手动模拟样例。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1010000;
const int mod = 1e9+7;
int n,T;
bool f[N],g[N],preg[N],preg2[N];
char s[N];
int ret[N],ret2[N],cnt[N],cnt2[N];
void work(bool *g,int *ret,int n) {
for(int i = 1; i <= n; i++) ret[i]=1<<30;
int fo=n+1,lo=-1;
for(int i = 1; i <= n; i++) {
if (g[i]) {
if (fo==n+1) fo=i;
lo=i;
}
}
if (fo>lo) {
for(int i = 1; i <= n; i++) ret[i]=0;
return;
}
for(int i = 1; i <= n; i++) {
//preg前缀0的个数是奇数(1)还是偶数(0)
//preg2前缀1的个数是奇数(1)还是偶数(0)
//cnt[i]为[1,i]中preg为奇数的位置的个数
//cnt2[i]为[1,i]中preg2为奇数的位置的个数
preg[i]=preg[i-1]^g[i]^1;
preg2[i]=preg2[i-1]^g[i];
cnt[i]=cnt[i-1]+preg[i];
cnt2[i]=cnt2[i-1]+preg2[i];
// cout<<i<<" "<<cnt[i]<<endl;
}
for(int i = 1; i <= lo; i++) {
if (i<=fo) {
int fw=i,lw=lo;
if (i==lo) {
ret[i]=min(ret[i],3);
continue;
}
int ans=lw-fw;
//前缀为0个数为奇数,出发点在fw,i的值固定为0,需要来回的次数。
if (preg[fw-1]) ans+=2*(cnt[lw-1]-cnt[fw-1]);
else ans+=2*(lw-fw-cnt[lw-1]+cnt[fw-1]);
//区间总共偶数个零ans--,出发点在i,区间偶数个零停在lo-1处,最后一步不走。
if (preg[lw-1]^preg[fw-1]^1) ans--;
ret[i]=min(ret[i],ans);
} else {
//[fw,i]为第一段,[i,lo]为第二段
//先走到最左,走过一遍后,被走过的位置1变成0,0变成1,所以用
int fw=fo,lw=lo;
int ans=i-fo+lw-fw;
//到达最左后出发点为fw,fw的值固定为0,故同上操作。
if (preg2[fw-1]) ans += 2*(cnt2[i-1]-cnt2[fw-1]);
else ans+=2*(i-fw-cnt2[i-1]+cnt2[fw-1]);
//到达此处时已经到达i处,且i以前全为0,但i自己的值不固定
int x=preg2[i-1]^preg2[fw-1]^1;
//前缀0的个数要与前一段区间的奇偶行相反,
//x为1则代表从i的地方出发i的位置上为1等同于preg[i-1]为奇数的情况,都要在i-1与i之间来回一次(即ans+=2),
//否则i的位置上为0等同于preg[i-1]为0的情况
if (x==preg[i-1]) ans+=2*(cnt[lw-1]-cnt[i-1]);
else ans+=2*(lw-i-cnt[lw-1]+cnt[i-1]);
//若x=1,则第一段区间零的个数为偶数,则第二段区间零的个数为偶数,和为偶数;
//若x=0,则第一段区间零的个数为奇数,则第二段区间零的个数为奇数,和为偶数。
if (x^preg[i-1]^preg[lw-1]) ans--;
ret[i]=min(ret[i],ans);
}
}
}
void solve() {
scanf("%d",&n);
scanf("%s",s+1);
for(int i = 1; i <= n; i++) g[i]=(s[i]=='1');
work(g,ret,n);
reverse(g+1,g+n+1);
work(g,ret2,n);
LL ans=0;
for(int i = 1; i <= n; i++) {
ret[i]=min(ret[i],ret2[n+1-i]);
ans=(ans+(LL)i*ret[i])%mod;
}
printf("%lld\n",ans);
}
int main() {
#ifdef LOCAL
freopen("input.txt","r",stdin);
#endif // LOCAL
for (scanf("%d",&T); T; T--) solve();
}