题目链接
题目描述
生物学家小明正在研究一种特殊的细胞,其增殖遵循规律:种群数量 ,其中
是增殖基数,
是稳定基数,
是增殖周期(
)。
给定 条观测记录
,以及
组假说
(对应
和
),请计算:
- 总共有多少条记录符合该模式?
- 单个固定的
值所能对应的最高重复观测次数(增殖峰值)是多少?
数据范围:
(数据保证已按从小到大排列)
解题思路
由于观测记录 最大为
,且增殖基数
和稳定基数
均为非负数,我们可以针对不同的
值进行处理:
-
统计频次:
使用map<int, int>统计中每个数值出现的次数。
-
分类讨论
:
:由于
,则
,规律简化为
。只需查看记录中
的频次。
:对于任何
,
,规律简化为
。只需查看记录中
的频次。
:
随
的增加呈指数级增长。因为
且
,则
的最大取值约为
(
)。
- 枚举
,计算
。
- 如果
,则停止枚举。
- 在频次表中查询
,累加总记录数,并维护最大频次作为增殖峰值。
- 枚举
-
复杂度分析:
或
时,查询时间为
。
时,枚举次数极少(最多 30 次),查询总时间为
。
- 总时间复杂度完全可以承受。
代码
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
map<int, int> cnts;
for (int i = 0; i < n; ++i) {
int c;
cin >> c;
cnts[c]++;
}
while (m--) {
long long x, y;
cin >> x >> y;
long long total = 0;
int peak = 0;
if (x == 0) {
if (y >= 1 && y <= 1000000000 && cnts.count((int)y)) {
total = cnts[(int)y];
peak = cnts[(int)y];
}
} else if (x == 1) {
long long val = 1 + y;
if (val <= 1000000000 && cnts.count((int)val)) {
total = cnts[(int)val];
peak = cnts[(int)val];
}
} else {
long long curr = x;
while (curr + y <= 1000000000) {
int val = (int)(curr + y);
if (cnts.count(val)) {
total += cnts[val];
peak = max(peak, cnts[val]);
}
// 检查下一步是否会溢出 long long 或超过最大记录值
if (1000000000 / x < curr) break;
curr *= x;
}
}
cout << total << " " << peak << "\n";
}
return 0;
}
import java.util.Scanner;
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
HashMap<Integer, Integer> cnts = new HashMap<>();
for (int i = 0; i < n; i++) {
int c = sc.nextInt();
cnts.put(c, cnts.getOrDefault(c, 0) + 1);
}
for (int i = 0; i < m; i++) {
long x = sc.nextLong();
long y = sc.nextLong();
long total = 0;
int peak = 0;
if (x == 0) {
int c = cnts.getOrDefault((int) y, 0);
total = c;
peak = c;
} else if (x == 1) {
int val = (int) (1 + y);
int c = cnts.getOrDefault(val, 0);
total = c;
peak = c;
} else {
long curr = x;
while (curr + y <= 1000000000) {
int val = (int) (curr + y);
if (cnts.containsKey(val)) {
int c = cnts.get(val);
total += c;
peak = Math.max(peak, c);
}
if (1000000000 / x < curr) break;
curr *= x;
}
}
System.out.println(total + " " + peak);
}
}
}
def solve():
n, m = map(int, input().split())
records = list(map(int, input().split()))
cnts = {}
for val in records:
cnts[val] = cnts.get(val, 0) + 1
for _ in range(m):
x, y = map(int, input().split())
total = 0
peak = 0
if x == 0:
c = cnts.get(y, 0)
total, peak = c, c
elif x == 1:
c = cnts.get(1 + y, 0)
total, peak = c, c
else:
curr = x
while curr + y <= 1000000000:
val = curr + y
if val in cnts:
c = cnts[val]
total += c
if c > peak:
peak = c
curr *= x
print(total,peak)
if __name__ == "__main__":
solve()
算法及复杂度
- 算法:哈希表/映射统计频次 + 分类讨论。利用
时指数爆炸的特性,极大地减少了搜索空间。
- 时间复杂度:
。其中
用于 C++ 的
std::map构建,Java 和 Python 使用哈希表可优化至。
- 空间复杂度:
。用于存储观测记录的频次映射。

京公网安备 11010502036488号