小苯的美丽区间
[牛客链接](https://www.nowcoder.com/practice/b80c412275d44f2c8312cfedaa630faa)
题意
一个正整数 是「美丽数」当且仅当它是
的幂次。美丽值定义为
(即不断除以
的次数),非美丽数的美丽值为
。
给定长度为 的正整数数组
,求所有连续子数组之和的美丽值之和。
思路
枚举 的幂次 + 前缀和哈希
暴力枚举所有子数组是 ,但注意到一个子数组和
只有在
时才有贡献
,而
的取值只有
种(
为数组总和),这就为我们打开了突破口。
核心思路:把"枚举子数组"转化为"枚举目标值"。
设前缀和 。子数组
的和为
。对于固定的
,我们要统计满足
的有序对
(
)的个数,然后乘以
计入答案。
这就是经典的「两数之差为定值」问题——从左到右扫描 ,用哈希表记录之前出现过的前缀和及其次数,每次查找
是否在表中即可。
时间分析: 最多到
,每轮
,总计
。由于
,完全够用。
以样例 验证:前缀和为
。
:差为
的对有
,共
对,贡献
。
:差为
的对有
,共
对,贡献
。
:差为
的对有
,共
对,贡献
。
总计 ,与预期一致。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
vector<long long> a(n);
long long total = 0;
for (int i = 0; i < n; i++) {
scanf("%lld", &a[i]);
total += a[i];
}
long long ans = 0;
for (int k = 0; (1LL << k) <= total; k++) {
long long pw = 1LL << k;
unordered_map<long long, int> cnt;
cnt.reserve(n + 1);
long long prefix = 0;
cnt[0] = 1;
for (int i = 0; i < n; i++) {
prefix += a[i];
auto it = cnt.find(prefix - pw);
if (it != cnt.end()) {
ans += (long long)k * it->second;
}
cnt[prefix]++;
}
}
printf("%lld\n", ans);
}
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine().trim());
StringBuilder sb = new StringBuilder();
while (t-- > 0) {
int n = Integer.parseInt(br.readLine().trim());
StringTokenizer st = new StringTokenizer(br.readLine().trim());
long[] a = new long[n];
long total = 0;
for (int i = 0; i < n; i++) {
a[i] = Long.parseLong(st.nextToken());
total += a[i];
}
long ans = 0;
for (int k = 0; (1L << k) <= total; k++) {
long pw = 1L << k;
HashMap<Long, Integer> cnt = new HashMap<>();
cnt.put(0L, 1);
long prefix = 0;
for (int i = 0; i < n; i++) {
prefix += a[i];
Integer c = cnt.get(prefix - pw);
if (c != null) {
ans += (long) k * c;
}
cnt.merge(prefix, 1, Integer::sum);
}
}
sb.append(ans).append('\n');
}
System.out.print(sb);
}
}
复杂度分析
- 时间复杂度:
,其中
为数组总和。外层枚举
个幂次,内层每次
哈希扫描。
- 空间复杂度:
,哈希表存储前缀和。

京公网安备 11010502036488号