組合數學 (習題): Mehta and the Typical Supermarket (HackerRank)

Mehta and the Typical Supermarket

題目大意

NN 種硬幣, 每種硬幣無限個. 給定一個區間 [L,R][L, R], 問裏面有多少個數字可以由NN 種硬幣中的某一種組合出來. 也就是說問你區間內有多少個數可以被至少一枚硬幣的面值整除

思路

典型的容斥原理, 比如有面值 2 和 3, 區間爲 [1,10][1, 10], 那麼其中可以被組合出來的數有 {2,3,4,6,8,9,10}\{2, 3, 4, 6, 8, 9, 10\}, 很容易看出來, 如果一個數是這兩個數的最小公倍數, 那麼這個數應該被減掉 (係數爲 1-1), 同理, 如果一個數是其中三個數的最小公倍數, 那麼其係數應爲 +1+1

代碼

def gcd(a, b):
	if b == 0:
		return a
	return gcd(b, a % b)

def lcm(a, b):
	return result = a * b // gcd(a, b)

# 給定區間 L, R, 可以被 value 整除的數的個數
def nPlan(value, L, R):
	right = R // value
	left = L // value
	if L % value == 0:
		left -= 1
	return right - left

def _solve(val, i, count, L, R):
	if val > R:
		return 0
	if count == 0:
		return nPlan(val, L, R)
	result = 0
	for j in range(i+1, N):
		result += _solve(lcm(val, coins[j]), j, count-1, L, R)
	return result
	
def solve(count, L, R):
	result = 0
	for i in range(N):
		result += _solve(coins[i], i, count-1, L, R)
	return result

_N = int(input())
N = 0
coins = []

for i in range(_N):
	c = int(input())
	# 如果某一個硬幣的面值被另一個整除, 那麼這個硬幣就沒用了
	unique = True
	for j in range(N):
		if coins[j] % c == 0:
			coins[j] = c
			unique = False
			break
		if c % coins[j] == 0:
			unique = False
			break
	if unique:
		coins.append(c)
		N += 1

for _ in range(int(input())):
	L, R = map(int, input().split())
	result = 0
	for i in range(1, N+1):
		result += (-1)**(i-1) * solve(i, L, R)
	print(result)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章