20180530模拟赛T2——绀碧之棺
题目背景
qiancl 得到了一张藏宝图,上面写了一道谜题。
题目描述
定义\(F(n)\)为 n 在十进制下各个数位的平方和,求区间\([a,b]\)中有多少\(n\)满足\(k\times F(n) = n\)。
输入描述
一行三个正整数\(k,a,b\)。
输出描述
一行一个整数表示满足条件的\(n\)的个数。
样例输入
51 5000 10000
样例输出
3
数据范围及提示
测试数据 | 对应数据范围 |
---|---|
其中12个测试点 | \(1\le k,a,b\le 105\) |
其中6个测试点 | \(233\le k\le 250\),且\(1\le a,b\le10^8\) |
剩下32个测试点 | \(1\le k,a,b\le 10^{18}\) |
样例中满足的\(3\)个\(n\)分别是\(7293,7854,7905\)。
题解
开始被\(10^{18}\)的数据范围给吓到了,%你赛结束后听说有人打了数位dp(代码看这里)。orz
然而正解是枚举😄。
开始我没想那么多,就打了个普通的枚举,然后开始考虑优化。
首先,不难发现\(k\mid n\),于是我们就可以让\(n\) k个k个地加。
然后我们就考虑一下缩小枚举区间:
首先\(n\)是要求的,无法考虑在此方向拓展;
\(k\)于是我们就想到\(F(n)\),考虑到\(n \le 10^{18}\),又因为题目中明确说明“在十进制下”,于是我们就不难发现\(F(n)\le 9^2\times 18 = 1458\)(每一位都取\(9\))。又因为我们是\(k\)位\(k\)位枚举的,所以我们最多只需枚举\(1458\)次。
注意开long long
。
代码
#include <fstream>
#include <algorithm>
using namespace std;
ifstream fin("coffin.in");
ofstream fout("coffin.out");
typedef long long LL;
LL a, b, k;
const int sqr[] = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81};
const int kk = 81*18;
inline LL F(LL x)
{
LL ans = 0;
while(x)
{
ans += sqr[x%10];
x /= 10;
}
return ans;
}
inline bool check(LL n)
{
return F(n)*k == n;
}
int main()
{
int ans = 0;
fin >> k >> a >> b;
if(a == b)
{
fout << check(a);
return 0;
}
LL l = (a%k) ? ((a/k)+1)*k : a;
LL r = min((kk*k), b);
for(LL i = l; i <= r; i += k)
if(check(i))
ans++;
fout << ans << '\n';
return 0;
}