2024牛客五一集训派对day2:The Crime-solving Plan of Groundhog(含证明)
https://ac.nowcoder.com/acm/contest/80998/I
题目大意:
给定 n n n 个0~9的整数,用这些数码拼凑出 2 2 2 个整数,求所有可能的最小乘积
思路:
一个因数是:最小的非零数(如果有多个,只取其中一个)
另一个因数:删除选走的那个,剩下的非零数从小到大排序,然后所有0插在第一个数后面
因为涉及到高精度,所以用Python(懒得写高精度bushi
正确性证明
先不考虑数码中包含0的情况,假设所有数码都属于1~9,研究这个子问题:
-
引理1:如果 A A A , B B B 分配的数码都已经确定,那么如果想最小化乘积,就要使A,B的所有数码升序排列。(这个太显然就不证明了)
-
引理2:如果 A A A 只选 1 1 1 个数码, B B B 选 ( n − 1 ) (n-1) (n−1) 个数码,(根据引理 1 1 1 , B B B 升序排列),这种情况下, A A A 选择最小的数能使得 A A A 和 B B B 乘积最小
证明:(形式化的就不写了,一图胜千言)
-
如果不限制“ 1 1 1 个因数 1 1 1 个数码,另一个因数 ( n − 1 ) (n-1) (n−1) 个数码”,而也考虑到其他情况,比如“一个因数分配 2 2 2 个数码,另一个因数分配 ( n − 2 ) (n-2) (n−2) 个数码” ,会不会答案就不是我们这个了呢
答:不会,还是用图证明:
考虑给定数码中有0的情况
对于每一个 0 0 0 :
如果给 B B B ,那么一定是插在第一个数字后面,否则只会更大
那么如果插 A A A 后面呢?
AC code:
def solve():
for i in range(t):
n = int(input())
a = input().split()
a.sort()
i = 0
while a[i] == '0':
i += 1
x = a[i]
y = a[i + 1] + '0' * i + "".join(a[i + 2:])
print(int(x) * int(y))
t = int(input())
for i in range(t):
solve()