F. Awesome Substrings
time limit per test
8 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
Let's call a binary string ss awesome, if it has at least 11 symbol 1 and length of the string is divisible by the number of 1 in it. In particular, 1, 1010, 111 are awesome, but 0, 110, 01010 aren't.
You are given a binary string ss. Count the number of its awesome substrings.
A string aa is a substring of a string bb if aa can be obtained from bb by deletion of several (possibly, zero or all) characters from the beginning and several (possibly, zero or all) characters from the end.
Input
The first line contains the string ss (1≤|s|≤2000001≤|s|≤200000) consisting only of zeros and ones.
Output
Output a single number — the number of awesome substrings of ss.
Examples
input
Copy
111
output
Copy
6
input
Copy
01010
output
Copy
10
input
Copy
0000
output
Copy
0
input
Copy
1111100000
output
Copy
25
Note
In the first sample, all substrings of ss are awesome.
In the second sample, we have the following awesome substrings of ss: 1 (22 times), 01 (22 times), 10 (22 times), 010 (22 times), 1010, 0101
In the third sample, no substring is awesome.
题意:给定一个01串,求有多少个子串中1的个数可以被该子串长度整除。
分析:朴素的想一下,可以预处理一个前缀和来维护区间1个数,然后再枚举两个端点,如果那么这个区间就可以计数。
同时注意到当k变大时,区间1的数量会变少;当1的数量变多时,k值一定会变小。显而易见的,若枚举1的个数,每次枚举可以O(n)计算得到,只需要尺取一下就可以了。同样的,枚举k的值,只需要计算有多少对就可以了。
那么再来取一下k和1的个数的关系,,即是。
那么这里设定一个大小t,1的个数小于等于t的情况可以O(tn)求出,1的个数大于t时一定有,那么此时只需要从1到n/t枚举k就可以了,把所有的i-pre[i]*k计算出来排序,再把相同的值取出来计数,但注意要舍掉num1<=t的情况,这种情况的复杂度为O(n(n/t)logn)。
那么只需要调一下t的大小让两种情况的复杂度尽可能接近就可以了。
#include <bits/stdc++.h>
using namespace std;
char s[200004];
int sum[200004];
pair<int,int>a[200004];
int main() {
scanf("%s", s + 1);
int n = strlen(s + 1);
int t = max(n/250,(int)sqrt(n));
int tt =n/t;
for (int i = 1; i <= n; ++i) {
sum[i] = sum[i - 1] + (s[i] == '1');
}
long long ans = 0;
for (int i = 1; i <= t; ++i) {
int r = 0, rr = 0;
int num = 0;
for (int l = 1; l <= n; ++l) {
while (num < i && r < n) {
num += (s[++r] == '1');
}
rr =max(rr,r);
while (rr < n && s[rr + 1] != '1')rr++;
if (num == i)ans += (rr - l + 1) / i - (r - l) / i;
num -= s[l] == '1';
}
}
for (int i = 1; i <= tt; ++i) {
for (int j = 1; j <= n; ++j) {
a[j] = make_pair(j-sum[j]*i,sum[j]);
}
a[n+1]=make_pair(0,0);
sort(a+1,a+1+n+1);
for (int l = 1, r; l <= n+1; l=r+1) {
r = l;
while(r <= n && a[r+1].first == a[l].first)r++;
int ll = l,rr = l;
for (ll = l; ll <= r; ++ll) {
while(rr <= r && a[rr].second - a[ll].second <= t)rr++;
ans += r - rr + 1;
}
}
}
cout<<ans<<endl;
}