小欧的等差数列
[题目链接](https://www.nowcoder.com/practice/7c29bf99543040efa8e493b803050bdc)
思路
给定等差数列 ,每次可以选两个数
,若
是整数,就把它加入集合。求集合最终最大元素个数。
核心观察:最小可达步长
不妨将所有元素平移,令首项为 ,集合变为
(平移不影响中点运算)。
取两个元素 和
,中点为
。要求它是整数,即
是偶数。
- 若
是奇数,则需要
为偶数(同奇偶),中点
,仍是
的整数倍,不产生新元素。
- 若
是偶数,则
恒为偶数,中点
,步长缩小为
。
反复对新集合继续操作,每次 含因子
时步长就可以再减半。设
(
为奇数,
为
的
-adic 赋值),则最终步长缩至
(奇数后无法再减半)。
推导答案
最终集合覆盖区间 中所有
的整数倍:
$$
特殊情况
:集合最多
个元素。
:所有元素相同,答案
。
样例验证
。
,
。答案
。
原集合 ,取相邻元素中点得
,最终集合
,共
个,正确。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
long long n, a, d;
cin >> n >> a >> d;
if(n <= 1 || d == 0){
cout << 1 << endl;
return 0;
}
if(d < 0) d = -d;
long long v = 0;
long long dd = d;
while(dd % 2 == 0){
dd /= 2;
v++;
}
cout << (n - 1) * (1LL << v) + 1 << endl;
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong(), a = sc.nextLong(), d = sc.nextLong();
if (n <= 1 || d == 0) {
System.out.println(1);
return;
}
if (d < 0) d = -d;
long v = 0, dd = d;
while (dd % 2 == 0) { dd /= 2; v++; }
System.out.println((n - 1) * (1L << v) + 1);
}
}
n, a, d = map(int, input().split())
if n <= 1 or d == 0:
print(1)
else:
if d < 0:
d = -d
v = 0
dd = d
while dd % 2 == 0:
dd //= 2
v += 1
print((n - 1) * (1 << v) + 1)
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
rl.on('line', (line) => {
let [n, a, d] = line.trim().split(' ').map(Number);
if (n <= 1 || d === 0) { console.log(1); return; }
if (d < 0) d = -d;
let v = 0, dd = d;
while (dd % 2 === 0) { dd = Math.floor(dd / 2); v++; }
console.log((n - 1) * Math.pow(2, v) + 1);
});
复杂度
- 时间复杂度:
,只需计算
中因子
的个数。
- 空间复杂度:
。

京公网安备 11010502036488号