给定一个包含 n 个元素的数组 a 和 q 个查询(用 l 和 r 表示一个范围),输出区间 l,r 中水仙花数的个数。在数论中,水仙花数(Narcissistic number),也被称为超完全数字不变数、自恋数或阿姆斯特朗数(Armstrong number),用来描述一个 n 位非负整数,其各位数字的 n 次方和等于该数本身,即 (d1d2⋯dn)=d1n+d2n+⋯+dnn。
输入格式:
第一行输入两个整数 n(1≤n≤105)、q(1≤q≤105);
第二行输出 n 个空格隔开的非负整数 ai(0≤ai≤109);
接下来 q 行,每一行两个整数 li,ri(1≤li≤ri≤n)。
输出格式:
输出 q 行,每一行输出区间 [li,ri] 水仙花数的个数。
输入样例:
5 2
1 11 2 22 3
1 3
4 5
输出样例:
2
1
样例解释
区间 [1,3] 有两个水仙花数 1 和 2;
区间 [4,5] 有一个水仙花数 3。
python
import sys
def main():
# 快速读取所有输入(因为数据量很大,用sys.read更快)
data = list(map(int, sys.stdin.read().split()))
ptr = 0 # 指针,用来逐个取数据
# 第一步:读n(数组长度)和q(查询次数)
n = data[ptr]
q = data[ptr+1]
ptr += 2
# 第二步:读数组a的n个元素
a = data[ptr:ptr+n]
ptr += n
# 预处理:提前算好0-9的1~10次方(因为a_i最大是1e9,最多10位)
# pre_pow[d][k] = 数字d的k次方
pre_pow = [[0]*(11) for _ in range(10)] # d是0-9,k是1-10
for d in range(10):
for k in range(1, 11):
pre_pow[d][k] = d ** k
# 第三步:标记每个元素是否是水仙花数(生成is_narc数组)
is_narc = [0] * n # 初始都是0(不是)
for i in range(n):
x = a[i]
if x == 0:
# 0是1位,0^1=0 → 是水仙花数
is_narc[i] = 1
continue
# 计算x的位数k
s = str(x)
k = len(s)
total = 0
temp = x
# 计算各位数字的k次方和
while temp > 0:
digit = temp % 10 # 取最后一位数字
total += pre_pow[digit][k] # 用预处理的次方,更快
temp = temp // 10 # 去掉最后一位
# 判断和是否等于原数
if total == x:
is_narc[i] = 1 # 是水仙花数,标记为1
# 第四步:计算前缀和数组(方便快速查询区间和)
# prefix[0] = 0,prefix[1] = is_narc[0],prefix[2] = is_narc[0]+is_narc[1]...
prefix = [0] * (n + 1)
for i in range(n):
prefix[i+1] = prefix[i] + is_narc[i]
# 第五步:处理每个查询
output = []
for _ in range(q):
l = data[ptr]
r = data[ptr+1]
ptr += 2
# 区间[l,r]的水仙花数个数 = 前缀和[r] - 前缀和[l-1]
cnt = prefix[r] - prefix[l-1]
output.append(str(cnt))
# 输出所有结果(批量输出更快)
print('\n'.join(output))
if __name__ == "__main__":
main()