目录
特殊日期
分糖果
三国游戏
平均
记一个日期为yy年mm月dd 日,统计从2000年1月1日(含)到2000000年1月1日(含),有多少个日期满足年份yy是月份mm的倍数,同时也是dd的倍数。
题目链接
https://www.lanqiao.cn/problems/3495/learning/?page=1&first_category_id=1&sort=students_count&category_id=3&name=%E7%89%B9%E6%AE%8A%E6%97%A5%E6%9C%9F
典型的使用枚举思想,可以从2000年1月1日(含)到2000000年1月1日(含)每天是否符合特殊日期的要求进行枚举,符合条件计数就加1
mouth1 = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # 平年每个月天数列表,这里为了与月份统一下标,所以第一个为0
mouth2 = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # 闰年每个月天数列表
def fun(x): # 判断闰年函数
if (x % 4 == 0 and x % 100 != 0) or x % 400 == 0: # 能被4整除且不能被100整除,或者能被400整除
return 1
else:
return 0
ans = 0
for i in range(2000, 2000000):
for j in range(1, 13): # 月份从1到12
if fun(i) == 0: # 如果是平年
for m in range(1, mouth1[j] + 1): # 日期从1到mouth[j]
if i % j == 0 and i % m == 0: # i表示年份,j表示月份,m表示日期
ans = ans + 1
if fun(i) == 1: # 如果是闰年
for n in range(1, mouth2[j] + 1):
if i % j == 0 and i % n == 0:
ans = ans + 1
print(ans + 1)# 由于2000000.1.1以上循环没有但是也满足,所以要加上
# 35813063
这里使用定义每个月份的天数的列表可以简化后面的代码,这个思想对做这种时间题很有帮助
遇到时间问题还是一种思想就是可以使用datetime类,是python非常好用的用于计算时间的自带类,该类的使用方法可以查看我上次发的资源
https://download.csdn.net/download/m0_62574258/88760682
例如下题
对于一个日期,我们可以计算出年份的各个数位上的数字之和,也可以分别计算月和日的各位数字之和。请问从1900年1月1日至9999年12月31日,年份的数位数字之和等于月的数位数字之和加日的数位数字之和。例如,2022年11月13日满足要求,因为2+0+2 +2 =(1+1)+(1+3)。请提交满足条件的日期的总数量。
import datetime
def fun(x):
return sum(int(i) for i in str(x)) # 定义fun函数,用于计算数字的和
# 定义开始和结束日期范围
d1 = datetime.datetime(1900, 1, 1)
d2 = datetime.datetime(9999, 12, 31)
# 计算开始和结束日期之间的总天数
y = (d2 - d1).days
ans = 0
# 遍历日期范围内的每一天
for i in range(y):
# 从当前日期中提取年、月和日
a = d1.year
b = d1.month
c = d1.day
# 检查年份的数字和是否等于月份数字和加上日期数字和
if fun(a) == fun(b) + fun(c):
ans = ans + 1
# 使用一天的时间增量移动到下一天
d1 = d1 + datetime.timedelta(days=1)
# 打印结果
print(ans)
两种糖果分别有 9 个和 16 个,要全部分给 7 个小朋友,每个小朋友得到的糖果总数最少为 2 个最多为 5 个,问有多少种不同的分法。 只要有其中一个小朋友在两种方案中分到的糖果不完全相同,这两种方案就算作不同的方案。
题目链接
https://www.lanqiao.cn/problems/4124/learning/?page=1&first_category_id=1&sort=students_count&category_id=3&name=%E5%88%86%E7%B3%96%E6%9E%9C
使用递归思想,对于每个孩子使用两个for循环分配两种糖果的个数,当一个孩子分配完时再递归分配下一个孩子,此时糖果数量要对应的扣除上次分配出去的,如果7个孩子都分配完且糖果没有剩余,则算一种方案
ans = 0
def dfs(child, n, m):
global ans # 先声明ans是全局变量,否则函数内部的操作变量ans不会影响到函数外的ans
if child == 0 and n == 0 and m == 0: # 如果孩子数和两种糖果都分配完了即满足条件
ans += 1
for i in range(n + 1): # 第一种糖果
for j in range(m + 1): # 第二种糖果
if 2 <= i + j <= 5:
dfs(child - 1, n - i, m - j) # 继续递归对下一个孩子进行分配
dfs(7, 9, 16) # 7个孩子,第一种糖果有9个,第二种糖果有16个
print(ans)
#5067671
小蓝正在玩一款游戏。游戏中魏(X)、蜀(Y)、吴(Z)三个国家各自拥有一定数量的士兵X,Y,Z(一开始可以认为都为0)。游戏有n个可能会发生的事件,每个事件之间相互独立且最多只会发生一次,当第i个事件发生时会分别让X,Y ,Z增加Ai,Bi,Ci,当游戏结束时(所有事件的发生与否已经确定),如果X,y,Z的其中一个大于另外两个之和,我们认为其获胜。例如,当X >Y +Z时,我们认为魏国获胜。小蓝想知道游戏结束时如果有其中一个国家获胜,最多发生了多少个事件?如果不存在任何能让某国获胜的情况,请输出-1。
输入格式
输入的第一行包含一个整数n。
第二行包含n个整表示Ai,相邻整数之间使用一个空格分隔。
第三行包含n个整数表示Bi,相邻整数之间使用一个空格分隔。
第四行包含n个整数表示Ci,相邻数之间使用一个空格分隔。
样例输入
3
1 2 2
2 3 2
1 0 7
样例输出:2
题目链接
https://www.lanqiao.cn/problems/3518/learning/?page=1&first_category_id=1&sort=students_count&category_id=3&name=%E4%B8%89%E5%9B%BD%E6%B8%B8%E6%88%8F
这里有个技巧就是每次三个国家都会增加,我们只需要计算相对增加量,然后对三个国家各自胜利分类讨论,因为我们可以控制哪些事件先发生哪些事件后发生,所以最后只需要使用贪心算法的思想,相对增量越少的时间越先发生就能使用最多的事件数
n = int(input())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
c = list(map(int, input().split()))
x = []
y = []
z = []
for i in range(n):
x.append(a[i] - b[i] - c[i]) # 存储每个事件魏国相比较其它两国的相对增量
y.append(b[i] - a[i] - c[i]) # 存储每个事件蜀国国相比较其它两国的相对增量
z.append(c[i] - a[i] - b[i]) # 存储每个事件吴国相比较其它两国的相对增量
# 由于三国一开始都是0,所以只要当所有发生事件的相对增量和大于0即胜利
# 将相对增量排序,要求最大发生事件数,应该让相对增量为正数全部发生,然后相对增量为负数的从大到小发生,直到相对增量和大于0
# 可以认为所有事件按贡献的大小从大到小的顺序发生,所以将相对增量降序排序
x.sort(reverse=True)
y.sort(reverse=True)
z.sort(reverse=True)
def win(p): # 求p国获胜的最大发生事件数
sum = 0
for i in range(n):
sum = sum + p[i]
if sum < 0:
return i
return 0
print(max(win(x), win(y), win(z))) # 依次求x国、y国、z国胜利的最大发生事件数,然后再取最大值
有一个长度为n的数组(n是10的倍数),每个数a都是区间[0,9]中的整数。小明发现数组里每种数出现的次数不太平均,而更改第i个数的代价为bi,他想更改若干个数的值使得这10种数出现的次数相等(都等于n/10),请问代价和最少为多少。
题目链接
https://www.lanqiao.cn/problems/3532/learning/?page=1&first_category_id=1&sort=students_count&category_id=3&name=%E5%B9%B3%E5%9D%87
输入格式
输入的第—行包含—个正整数n。
接下来n行,第i行包含两个整数ai,bi,用一个空格分隔。
样例输入
10
1 1
1 2
1 3
2 4
2 5
2 6
3 7
3 8
3 9
4 10
样例输出:27
还是使用贪心思想,从0到9开始遍历,看哪个数字的数量超过了n/10,某个数字超过平均个数多少个就要改多少个,而改哪几个是由代价决定的,代价越小越先被改变。这里使用二维列表,b列表中存放了10个一维列表,0到9每种数字的所有代价分别存在这10个一维列表
n = int(input())
sum = 0 # 代价和
b = [[] for i in range(10)] # 创建二维列表,b[i]存储i数字的所有代价
for i in range(n):
o, e = map(int, input().split()) # o是数字几,e是该数的代价
b[o].append(e) # 根据数字找到对应哪个列表,然后把该数的代价加入到该列表中
ave = n // 10
for i in range(10): # 数字从0到9遍历
if len(b[i]) > ave: # len(b[i])表示i数字的个数,如果大于平均值,多出来的就要变成其他数
num = len(b[i]) - ave # 与平均值作差,差值num表示有多少个变成别的数
b[i].sort() # 将i数字的所有代价升序排序
for j in range(num): # 从中取代价最小的num个数,从开头开始取,一直取num个
sum = sum + b[i][j] # 把取出的数需要的代价加上sum
print(sum)