• 羊工八刀:

  • 直接写必然会超时,但是pta估计就能交上去,咳咳!

  • 先说思路:枚举每个位置直接算肯定会爆炸,所以我们发现到当前的1的总平方和仅仅受到其前面的1影响,很显然是一道DP

  • 每次枚举到一个新的1,当前的由这个1开始的总平方和就是(上一个1的总平方和)加上(上一个1的前面所有的1到上一个1的距离和2当前1到上一个1的距离)加上(当前1的前面的1的总个数乘以当前1到上一个1的距离)加上(当前1到上一个1距离的平方)可能有点不好理解我举个例子

  • 对于10111

  • 枚举到第二个1时平方和等于2显而易见

  • 枚举到第三个1时平方和等于10显而易见

  • 枚举到最后一个1时当前的这个1前面的1前面所有1到前面1的距离就是4

  • sum = 10 + 2 * 4 * 1 + 2 * 1 * 1 + 1 * 1 = 21

  • 为什么会这样,上面的公式时什么意思呢

  • 其实就是一个完全平方公式

  • 上一个sum就是上一个1的前面的1到上一个1的距离平方和,我们写成:

  • x1^2 + x2^2 + ... + xn^2

  • 统计的当前1的前一个1的前面的所有1到上一个1的距离和就是:

  • x1 + x2 + ... + xn

  • 当前1到上一个1的距离就是y

  • 所以上面描述的哪一大串公式就是x1^2 + x2^2 + ... + xn^2 + 2 * (x1 + x2 + ... + xn) * y + y + y + ... + y(前面1的个数个) + y

  • 含义就是(x1^2 + 2 * x1 * y + y * y) + (x2^2 + 2 * x2 * y + y * y) + ... + (xn^2 + 2 * xn * y + y * y) + y * y

  • 也就是当前的1前面所有1到当前1的距离平方和

#include<iostream>
using namespace std;
const int N=1e6+10,mod=1e9+7;
typedef long long ll;
char s[N];
int main()
{
    int t;cin>>t;
    while(t--)
    {
        int n,pos=-1;cin>>n;
        scanf("%s",s);
        ll num=0,len=0,cnt=0,sum=0;
        ll ans=0;
        for(int i=0;i<n;i++)
        {
            if(pos==-1&&s[i]=='1')
            {
                pos=i;continue;
            }
            if(s[i]=='1')
            {
                num++;
                sum+=2*len*(i-pos)+(i-pos)*(i-pos)*num,sum%=mod;
                len+=num*(i-pos),len%=mod;
                ans+=sum,ans%=mod;
                pos=i;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}