1 条题解
-
0
自动搬运
来自洛谷,原作者为

qiuqiuyaq
一枚蒟蒻的红题选手搬运于
2025-08-24 22:41:42,当前版本为作者最后更新于2023-03-08 21:51:54,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题意简述
给出 个整数 ,需要从中挑下标不同的两个数,例如挑选 和 可以拼接为 或者 ,问一共有多少种拼接方式使得拼接之后的数是 的倍数?
注意
拼接的顺序不同算不同的方案,即使 等于 。
时间复杂度分析
为 时间复杂度要控制在 以内。
实现思路
考虑枚举加优化。
我们可以枚举后面这个数 ,枚举完 之后, 就固定了,然后再枚举一下前面有多少种不同的选法,使得 这个数是 的倍数。
用 表示 的位数,例如
, 的位数为 位。
当我们枚举 之后, 与 都是固定的,变量就只剩下 ,相当于问有多少个 使得 恰好能够整除 ?
可以用哈希表或者数组存储 ,所有数的范围是从 到 ,位数最多是 位。
开 个哈希表,第 个哈希表存储 , 的余数出现的次数。
预处理的时间复杂度为 的个数 。
公式推导
由
得
在第 个哈希表中查找有多少个 的余数等于 ,查询哈希表的时间复杂度为 。
本题步骤
-
枚举整体数组来预处理 数组。
-
再依次枚举这个数组中的每个数 。然后在上述预处理之后的数组中找出一个或多个数字,这一个或多个数字 满足 == 。
-
其中每次算结果的时候需要判重。因为之前在计算预处理数组时候一定会枚举到自身,并将自身 的 次方 存入到 数组中。因此在这次计算结果的时候一定就要判断有无自己,有则结果减 。
一些细节
利用
res += s[len][(k - t) % k]得到数学中的余数,例如在 C++ 中 ,而在数学中答案应该是如果我们想得到余数 ,可以用
(k - t) % k,实现#include <iostream> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int N = 100010; int n, m; //用a数组存储每个数 k只有10^5 开一个数组当作哈希表即可 int a[N], s[11][N]; int main() { scanf("%d%d", &n, &m); for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]); //枚举每个数 预处理哈希表 for (int i = 0; i < n; i ++ ) { LL t = a[i] % m; //枚举当前数在每种指数下%k的余数是多少 for (int j = 0; j < 11; j ++ ) { //第j个哈希表的余数是t s[j][t] ++ ; //幂次*10 t = t * 10 % m; } } LL res = 0; for (int i = 0; i < n; i ++ ) { LL t = a[i] % m; //求出ai的位数 int len = to_string(a[i]).size(); //位数为len 在第len个哈希表中查找有多少个 Aj 满足 Aj × 10^ki % k 的余数等于 -Ai res += s[len][(m - t) % m]; //余数为(m - t) % m LL r = t; //判断Ai本身是否也在统计的范围内-> 计算 Ai × 10^ki % k 是否等于 Ai while (len -- ) r = r * 10 % m; //满足说明计算重复需要-1 if (r == (m - t) % m) res -- ; } printf("%lld\n", res); return 0; } -
- 1
信息
- ID
- 8086
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者