题目
小蓝发现了一个有趣的数列,这个数列的前几项如下:
1,1,2,1,2,3,1,2,3,4,⋯
小蓝发现,这个数列前 1项是整数1,接下来2 项是整数1 至2,接下来3 项是整数1 至3,接下来4 项是整数1 至 4,依次类推。
小蓝想知道,这个数列中,连续一段的和是多少。
思路
将每段连续的123都视为一行,即1121231234有4行,第n行有1-n个数。首先得到起点所在的行,算出从数列第一项到该起点的和,对终点也做同样操作,将终点的和-起点的和得到这段的和输出。
但这样只能通过4个测试用例,其他用例运行超时。
看了题解,发现求这种数列的和有个数学公式:1+1+2+1+2+3+,,,,+1+2+,,,+N=N(N+1)(N+2)/6
但是还是超时???不理解 (搞错了 发现自己二分法的代码没有删掉之前的暴力)通过7个,另外3个 答案错误???可能是精度问题?(果然,将上面公式写为//就ac了,比赛要注意一下这个问题!)
代码
import os
import sys
# 请在此输入您的代码
def find_row(a):
# 使用二分法对该数所处行进行查找 最后返回l的值 即为该数所处行数
#row = 1 最开始没删这个 我还疑惑为啥还是超时!
#while((1 + row) * row / 2 < a):
#row += 1
r = 1000000000000
l = 1
while l <= r:
mid = int((r + l)/2)
if (1 + mid) * mid / 2 < a:
l = mid + 1
else:
r = mid - 1
return l
def get_sum_start(row, a):
# 得到整个数列到起点的和[1,a)
# 起点位于第row行
add = 0
global sum_dict
sum_dict = {}
if row == 1: #因为range(1,1)是不会进入循环的 因此1作为单独的情况处理
return 0
temp = 1
for i in range(2, row): #前n行(不包括row这一行)的和
if i in sum_dict.keys(): #使用一个字典来记录之前计算过的某一行的和 减少重复计算
add += sum_dict[i]
temp += i
continue
temp += i
add += temp
sum_dict[i] = temp
add += sum( x for x in range(1, a - int((row - 1) * row / 2))) + 1 #加的1就是第一行的1 a-int((row - 1) * row / 2)表示row这一行的和
return add
def get_sum_end(row, a):
# 大部分与get_sum_start同理
add = 0
if row == 1:
return 1
temp = 1
for i in range(2, row): #前n行的和
if i in sum_dict.keys():
add += sum_dict[i]
temp += i
continue
temp += i
add += temp
sum_dict[i] = temp
add += sum( x for x in range(1, a + 1 - int((row - 1) * row / 2))) + 1 # [0,b+1) = [0,b]
return add
global sum_dict
T = int(input())
result = []
for i in range(T):
start, end = map(int, input().split())
strat_row = find_row(start) #得到起点所处的行
end_row = find_row(end) # 终点所处的行
sum_start = get_sum_start(strat_row, start) #[1,a)的和
sum_end = get_sum_end(end_row, end) #[1, b]的和
result.append(sum_end - sum_start)
for i in result:
print(int(i), end= "\n")
# import os
# import sys
# # 请在此输入您的代码
# def find_row(a):
# # 使用二分法对该数所处行进行查找 最后返回l的值 即为该数所处行数
# r = 1000000000000
# l = 1
# while l <= r:
# mid = int((r + l)/2)
# if (1 + mid) * mid / 2 < a:
# l = mid + 1
# else:
# r = mid - 1
# return l
# def get_sum_start(row, a):
# # 得到整个数列到起点的和[1,a)
# # 起点位于第row行
# add = 0
# if row == 1: #因为range(1,1)是不会进入循环的 因此1作为单独的情况处理
# return 0
# add = int(((row-1)**3 + 3 * (row - 1)**2 + 2 * (row - 1)) //6)
# b = a - int((row - 1) * row / 2)
# add += int((b-1)*b/2)
# return add
# def get_sum_end(row, a):
# # 与get_sum_start同理
# add = 0
# if row == 1:
# return 1
# add = int(((row-1)**3 + 3 * (row - 1)**2 + 2 * (row - 1)) //6)
# b = a + 1 - int((row - 1) * row / 2)#[1, b+1) = [1, b]
# add += int((b-1)*b/2)
# return add
# global sum_dict
# T = int(input())
# result = []
# for i in range(T):
# start, end = map(int, input().split())
# strat_row = find_row(start) #得到起点所处的行
# end_row = find_row(end) # 终点所处的行
# sum_start = get_sum_start(strat_row, start) #[1,a)的和
# sum_end = get_sum_end(end_row, end) #[1, b]的和
# result.append(sum_end - sum_start)
# for i in result:
# print(int(i), end= "\n")
题目
小蓝负责花园的灌溉工作。
花园可以看成一个n 行m 列的方格图形。中间有一部分位置上安装有出水管。
小蓝可以控制一个按钮同时打开所有的出水管,打开时,有出水管的位置可以被认为已经灌溉好。
每经过一分钟,水就会向四面扩展一个方格,被扩展到的方格可以被认为已经灌溉好。即如果前一分钟某一个方格被灌溉好,则下一分钟它上下左右的四个方格也被灌溉好。
给定花园水管的位置,请问k 分钟后,有多少个方格被灌溉好?
思路
深度遍历,对目前已灌溉方格的四邻居进行遍历,然后计数。
代码
import os
import sys
# 请在此输入您的代码
n, m = map(int, input().split())
t = int(input())
point = [[0 for i in range(m+1)] for i in range(n+1)] #用来存储某个方格是否被访问过 (m+1)(n+1)与题目中的下标对齐
location = []
for i in range(t):
x, y = map(int, input().split())
point[x][y] = 1
location.append([x, y])
k = int(input())
def Check(x, y):
if x >=0 and x<= n and y >=0 and y <= m and point[x][y] == 0: #边界检查以及是否被放翁检查
return True
else:
return False
nums = t #最初灌溉数量=水龙头的数量
offsets = [[0, 1], [0, -1], [1, 0], [-1, 0]]
for i in range(k):
temp = []
while len(location) != 0:
a, b = location.pop() #依次遍历目前已灌溉好的方格
for off_x, off_y in offsets:
now_x = a + off_x
now_y = b + off_y
if Check(now_x, now_y): #检查该方格是否合法
nums += 1
point[now_x][now_y] = 1
temp.append([now_x, now_y])# 用于存储下一分钟的起点
location = temp[:]
print(nums)