小苯认为一个数
是美丽数,当且仅当:如果将
不停除以
,直到
不整除
时停止,此时
恰好等于
。
现在小苯有一个长度为
的数组
,他想知道
中所有连续子数组的和的美丽值之和是多少,请你帮他算一算吧。
形式化的:记数字
的美丽值为
,则请你求出
。
形式化的:记数字
(其中
表示
数组在
这一段区间的所有元素之和。)
每个测试文件均包含多组测试数据。第一行输入一个整数代表数据组数,每组测试数据描述如下:
第一行输入一个正整数,表示数组
的长度。
第二行个正整数
,表示数组
。
(保证同一个测试文件中的测试数据里,的总和不超过
。)
对于每个测试数据,在单独的一行输出一个整数表示答案。
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(); }