题解:学而思编程 奇特的数
【题目来源】
题目来源:奇特的数
【题目描述】
给定一个 \(n \times n\) 的矩阵 \(a\),其中第 \(i\) 行第 \(j\) 列的元素 \(a_{ij}\) 等于 \(i\times j(1 \le i,j \le n)\)。
现在,给定一个整数 \(m\),请你计算 \(m\) 在矩阵中出现的次数。
【输入】
第一行一个整数 \(T\),表示共有 \(T\) 组测试数据。
每组数据包含两个整数 \(n,m\)。
【输出】
每组数据输出一行一个结果,表示 \(m\) 在矩阵中出现的次数。
【输入样例】
2
3 6
3 3
【输出样例】
2
2
【核心思想】
-
问题分析:给定 \(n \times n\) 矩阵,其中 \(a_{ij} = i \times j\)(\(1 \leq i, j \leq n\))。求整数 \(m\) 在矩阵中出现的次数。这是一个因子分解 + 约束计数问题,关键在于将矩阵元素转化为因子对,并统计满足条件的因子对数量。
-
算法选择:
- 因子对枚举:\(a_{ij} = m\) 等价于 \(i \times j = m\),即 \((i, j)\) 是 \(m\) 的一对因子
- 边界约束筛选:因子对需满足 \(1 \leq i \leq n\) 且 \(1 \leq j \leq n\)
-
关键步骤:
- 初始化:读取 \(T\)(测试组数)
- 处理每组数据:
- 读取 \(n\) 和 \(m\)
s = 0:计数器- 遍历 \(i\) 从 \(1\) 到 \(n\):
- 若 \(m \bmod i = 0\)(\(i\) 是 \(m\) 的因子):
- 令 \(j = m / i\)
- 若 \(j \leq n\)(\(j\) 在矩阵列范围内):
s++:因子对 \((i, j)\) 满足条件
- 若 \(m \bmod i = 0\)(\(i\) 是 \(m\) 的因子):
- 输出
s
-
时间/空间复杂度:
- 时间复杂度:\(O(T \times n)\),每组数据遍历 \(1\) 到 \(n\)
- 空间复杂度:\(O(1)\),仅需常数变量
-
因子分解的核心思想:
- 矩阵元素结构:\(a_{ij} = i \times j\) 将二维矩阵元素完全由行列下标的乘积决定,\(m\) 出现的次数等于 \(m\) 的因子对中两个因子均不超过 \(n\) 的对数
- 单向枚举:固定 \(i\) 从 \(1\) 到 \(n\),则 \(j = m / i\) 唯一确定,只需验证 \(j\) 是否为整数且在范围内,避免 \(O(n^2)\) 的矩阵遍历
- 对称性利用:因子对 \((i, j)\) 和 \((j, i)\) 对应矩阵中不同位置(除非 \(i = j\)),枚举 \(i\) 时自然覆盖所有情况
- 提前终止条件:\(m \bmod i = 0\) 时才有必要计算 \(j\),减少无效运算
- 适用于"乘积矩阵 + 值查询"类问题,因子分解将二维搜索降为一维枚举
【算法标签】
数学
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T; // 测试用例数
cin >> T;
for (int p = 0; p < T; p++) // 处理每个测试用例
{
long long n, m;
cin >> n >> m; // 输入n和m
long long s = 0; // 计数器
for (int i = 1; i <= n; i++) // 遍历i从1到n
{
if (m % i == 0 && m / i <= n) // 条件判断
{
s++; // 满足条件,计数加1
}
}
cout << s << endl; // 输出结果
}
return 0;
}
【运行结果】
2
3 6
2
3 3
2
浙公网安备 33010602011771号