一、审题
题目描述
珂朵莉有一个正整数数列 {an}\{a_n\}{an},对于所有的 i≥1i\geq 1i≥1,ai+1=ai×i+1a_{i+1}=a_{i}\times i+1ai+1=ai×i+1。
现在她定义了一个新的数列 {bn}\{b_n\}{bn},对于所有的 i≥1i\geq 1i≥1,bib_ibi 表示有多少个 aja_jaj,满足 1≤j<i1\leq j<i1≤j<i 且 aja_jaj 是 aia_iai 的因子。
请你帮助珂朵莉计算出数列 {bn}\{b_n\}{bn} 的前 NNN 项。
输入格式
输入文件的第一行包含一个整数 NNN。
输出格式
输出文件共 NNN 行,第 iii 行表示 bib_ibi 的值。
输入样例
10
输出样例
0
1
1
1
2
1
3
1
2
4
题目来源
2018 CSP-J No.3
二、思路
珂朵莉的数列 a1⋯na_{1\cdots n}a1⋯n 有一个特点:ai mod aj>0(i>j)a_i \bmod a_j>0(i>j)aimodaj>0(i>j)。因为如果存在i>ji>ji>j,满足aj∣aia_j|a_iaj∣ai,那么ai+1 mod aj=ai×i+1 mod aj=1a_{i+1}\bmod a_j=a_i\times i+1 \bmod a_j=1ai+1modaj=ai×i+1modaj=1,那么aj∣ai+1a_j|a_{i+1}aj∣ai+1,所以不满足原式。在这个性质的基础上,我们可以通过约数分块算法来统计每个数的因子个数,时间复杂度为 O(nn)O(n\sqrt n)O(nn)。
约数分块算法的基本思路是,将每个数 xxx 的因子分为两类:小于等于 x\sqrt xx 的因子和大于 x\sqrt xx 的因子。只需要先统计小于等于 x\sqrt xx 的因子数,然后再计算大于 x\sqrt xx 的因子数。这样,我们只需要枚举 n\sqrt nn 个因子即可完成统计。具体实现时,可以先预处理每个数的小于等于 n\sqrt nn 的因子个数,然后针对每个 iii,枚举其大于 i\sqrt ii 的因子,根据约数的对称性,即可计算出小于 i\sqrt ii 的因子个数,从而求出 bib_ibi。
时间复杂度分析:对于每个 xxx,通过约数分块算法只需要枚举 x\sqrt xx 个因子,因此时间复杂度为 O(nn)O(n\sqrt n)O(nn)。
三、示例代码
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
const int MAXN = 1005;
int b[MAXN];
vector<int> factors[MAXN]; // 存储每个数的因子
int main()
{
int n;
cin >> n;
// 预处理每个数的因子
for (int i = 1; i <= n; i++)
{
for (int j = 1; j * j <= i; j++)
{
if (i % j == 0)
{
factors[i].push_back(j);
if (j != i / j)
{
factors[i].push_back(i / j);
}
}
}
}
for (int i = 1; i <= n; i++)
{
// 先计算小于等于sqrt(i)的因子个数
for (int j = 0; j < factors[i].size(); j++)
{
if (factors[i][j] <= sqrt(i))
{
b[i]++;
}
}
// 再计算大于sqrt(i)的因子个数
for (int j = 0; j < factors[i].size(); j++)
{
if (factors[i][j] > sqrt(i))
{
if (factors[i][j] < i)
{
b[i]++;
}
}
}
cout << b[i] << endl;
}
return 0;
}
博客围绕珂朵莉数列问题展开,先给出题目描述、输入输出格式及样例,题目要求计算数列 {bn} 前 N 项。接着介绍思路,利用数列性质,通过约数分块算法统计因子个数,时间复杂度为 O(n√n),最后给出示例代码。
142

被折叠的 条评论
为什么被折叠?



