小苯认为一个数
是美丽数,当且仅当:如果将
不停除以
,直到
不整除
时停止,此时
恰好等于
。
现在小苯有一个长度为
的数组
,他想知道
中所有连续子数组的和的美丽值之和是多少,请你帮他算一算吧。
形式化的:记数字
的美丽值为
,则请你求出
。
形式化的:记数字
(其中
表示
数组在
这一段区间的所有元素之和。)
每个测试文件均包含多组测试数据。第一行输入一个整数代表数据组数,每组测试数据描述如下:
第一行输入一个正整数,表示数组
的长度。
第二行个正整数
,表示数组
。
(保证同一个测试文件中的测试数据里,的总和不超过
。)
对于每个测试数据,在单独的一行输出一个整数表示答案。
2 5 2 4 4 3 5 4 2 2 2 2
15 13
对于第二组测试数据:;
所有长度为的子区间和都是美丽的,因为
的二进制中只有一个
,其美丽值为
,因此总美丽值为
;
所有长度为的子区间和都是美丽的,因为他们的和都是
,
的美丽值为
,其总美丽值为
。
所有长度为的子区间和都不是美丽的,因此美丽值总和为
。
唯一一个长度为的子区间和是美丽的,其总和为
,美丽值为
;
综上,所有区间的总美丽值之和为:。
pre_sum[i] - pre_sum[j] = (1 << p)而等式右边只有log级别的,所以O(nlogn)就可以解决
#include <iostream>
#include <vector>
#include <set>
#include <map>
std::vector<long long> tar;
void solve() {
int n; std::cin >> n;
std::vector<int> a(n);
long long pre_sum = 0;
std::map<long long, int> mp;
mp[0] ++;
for (int i = 0; i < n; i ++) {
std::cin >> a[i];
pre_sum = pre_sum + a[i];
mp[pre_sum] ++;
}
pre_sum = 0;
long long ans = 0;
for (int i = 0; i < n; i ++) {
pre_sum += a[i];
for (int j = 0; tar[j] <= pre_sum; j ++) {
auto target = pre_sum - tar[j];
ans += mp[target] * j;
}
}
std::cout << ans << std::endl;
}
int main() {
int t = 1;
std::cin >> t;
tar.reserve(64);
for (int i = 0; i < 60; i ++) {
tar.push_back(1ll << i);
// std::cout << tar.back() << ' ';
}
// std::cout << std::endl;
while (t --) solve();
}