E.羊工八刀(预处理+前缀和优化)

思路:暴力枚举O(n^2)的复杂度显然会TLE。 我们可以将每个人位置预处理出来,再去计算每个位置能提供的贡献。 显然对于posipos_i,其贡献为: (posipos1)2+(posipos2)2+(posipos3)2+....+(posiposi1)2 (pos_i-pos_1)^{2}+(pos_i-pos_2)^{2}+(pos_i-pos_3)^{2}+....+(pos_i-pos_{i-1})^{2}

可以将其变形为:(posi)2(i1)+[(pos1)2+(pos2)2+....+(posi1)2]2posi(pos1+pos2+...+posi1)(pos_i)^{2}*(i-1)+[(pos_1)^{2}+(pos_2)^{2}+....+(pos_{i-1})^{2}]-2*pos_i*(pos_1+pos_2+...+pos_{i-1}) 显然前缀和预处理可以O(n)实现总贡献的计算。

code:

typedef long long ll;
using namespace std;
const int mod = 1e9 + 7, N = 1e6 + 10;
ll a[N], sum[N], sum2[N];

int main()
{
    std::ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

#ifdef ak
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int t;
    cin >> t;
    while (t--)
    {
        memset(sum, 0, sizeof sum);
        memset(sum2, 0, sizeof sum2);
        memset(a, 0, sizeof a);
        int n;
        cin >> n;
        string s;
        cin >> s;
        int idx = 1;
        for (int i = 0; i < s.length(); i++)
        {
            if (s[i] == '1')
            {
                a[idx++] = i + 1;
            }
        }
        for (int i = 1; i < idx; i++)
        {
            sum[i] = sum[i - 1] + a[i] * a[i];
            sum[i] %= mod;
            sum2[i] += a[i] + sum2[i - 1];
            sum2[i] %= mod;
        }
        ll ans = 0;
        for (int i = 1; i < idx; i++)
        {
            ll x = a[i] * a[i] * (i - 1) + sum[i - 1] - 2 * sum2[i - 1] * a[i];
            ans += x;
            ans %= mod;
        }

        cout << ans << endl;
    }
    return 0;
}