# 自己写的粗糙前缀和代码,超时了 n = int(input()) a = [int(i) for i ininput().split()] # 创建前缀和数组 b = [0]*n b[0] = a[0] for i inrange(1, n): b[i] = b[i-1] + a[i] # 利用滑动窗口求出区间乘积 ans = 0 # 区间长度 for l inrange(1,n+1): temp = 1 for right inrange(n): if right < l-1: temp *= a[right] elif right == l-1: # begin to judge temp *= a[right] if temp == b[right]: ans += 1 else: temp *= a[right] temp //= a[right-l] if temp == b[right] - b[right-l]: ans += 1 print(ans)
# 填充这几个辅助数组 cnt = 0# 记录当前非1元素前缀1的个数 for i inrange(n): if a[i] == 1: cnt += 1 else: # 每遇到一个非1元素,就存储该元素前连续1的个数,然后清零重新计数 one_cnt.append(cnt) cnt = 0 num.append(a[i]) if one_cnt: # 注意还要将最后一个非1元素右边的连续1的个数也记录下来 one_cnt.append(cnt) # 填充add数组 # 创建前缀和数组add[],add[i]是num[i]在原数组中的前缀和(包含它以及它以前所有元素的和) add = [0]*len(num) for i inrange(len(num)): if i == 0: add[0] = one_cnt[0] + num[0] else: add[i] = add[i-1] + one_cnt[i] + num[i] # 开始正式求解 ans = n # 每一个长度为1的区间都符合题意,一共有n个 # 整个原数组的元素和 all_sum = add[-1] + one_cnt[-1] # 遍历非1数组num for left inrange(len(num)-1): # create a variable to record the multiple result of all of the elements in the interval m = num[left] # 对left = 0特别处理 if left == 0: for r inrange(left+1,len(num)): m *= num[r] if m > all_sum: break diff = m - (add[r] - one_cnt[left]) if diff > 0: if diff <= one_cnt[r+1] + one_cnt[left]: # 这里的ll和rr记录了左右两侧最多能够取多少个1到当前的子序列中 # 相当于求一个长度为diff的滑块在长度为ll+rr的滑槽中滑动的位置数 # 受限于滑块本身的长度,部分坐标(共diff-1个)是取不到的,所以减去 ll = min(diff,one_cnt[left]) rr = min(diff,one_cnt[r+1]) ans += ll+rr-diff+1 elif diff == 0: ans += 1 continue
for right inrange(left+1,len(num)): # because the 1 will not change the result of multiple,so ignore them m *= num[right] if m > all_sum: # 乘积超过总和,直接排除 break # 再看乘积与区间和的差值 d = m - (add[right] - add[left-1] - one_cnt[left]) if d > 0: # 尝试用左右两侧的1补齐 if d <= one_cnt[right+1]+one_cnt[left]: # 可以补全 # 但因为1有多种取法,所以有多种情况 # ans += min()+1 + min()+1 - (d+1) l_case = min(d,one_cnt[left]) r_case = min(d,one_cnt[right+1]) ans += l_case+r_case-d+1 elif d == 0: ans += 1 print(ans)
例题 2:字串简写(蓝桥杯第14届省赛真题)
题目描述:
程序猿圈子里正在流行一种很新的简写方法:对于一个字符串,只保留首尾字符,将首尾字符之间的所有字符用这部分的长度代替。例如 internation-alization 简写成 i18n,Kubernetes (注意连字符不是字符串的一部分)简写成 K8s, Lanqiao 简写成 L5o 等。
在本题中,我们规定长度大于等于 K 的字符串都可以采用这种简写方法(长度小于 K 的字符串不配使用这种简写)。
给定一个字符串 S 和两个字符 c1 和 c2,请你计算 S 有多少个以 c1 开头 c2 结尾的字串可以使用这种简写。
# 可以直接暴力,但肯定会超时,这种题目评测数据很大,纯暴力拿不了几分 k = int(input()) s,c1,c2 = input().split() # 创建两个辅助数组,存储字符串中c1和c2字符的下标 begin = [] end = [] for i inrange(len(s)): if s[i] == c1: begin.append(i) if s[i] == c2: end.append(i) # 两重for循环判断每一对c1和c2是否符合题意 ans = 0 b = len(begin) e = len(end) startIndex = 0 for i inrange(b): for j inrange(startIndex, len(e)): # 如果不满足题意,直接跳过 if end[j]-begin[i]+1 < k: continue # 满足题意,直接利用end[]数组的长度计算出后续还有多少个符合条件的c2 ans += e - j # 更新startIndex,下一次从j开始搜索,因为 begin[i+1] > begin[i] startIndex = j # 直接结束本轮搜索 break print(ans)
defcheck(l): if l == 0: returnTrue global n,m,matrix, add # 检查是否存在符合题意的边长为l的正方形区间 for i inrange(n-l+1): for j inrange(m-l+1): # 计算区间和是否为0 temp = add[i+l-1][j+l-1] if i > 0and j > 0: temp = temp - add[i+l-1][j-1] - add[i-1][j+l-1] + add[i-1][j-1] elif i > 0and j == 0: temp = temp - add[i-1][j+l-1] elif i == 0and j > 0: temp = temp - add[i+l-1][j-1] if temp == 0: returnTrue returnFalse
n,m = map(int,input().split()) matrix = [] for i inrange(n): matrix.append([init(j) for j ininput().split()]) # 初始化二维前缀和数组 add = [[0]*m for i inrange(n)] for i inrange(m): add[0][i] = matrix[0][i] for i inrange(1,n): add[i][0] = matrix[i][0] for i inrange(1,n): for j inrange(1,m): add[i][j] = matrix[i][j] + add[i-1][j] + add[i][j-1] - add[i-1][j-1] # 二分法搜索区间和为0的最大正方形区间 left = 0 right = min(n,m) while left < right: mid = (left+right+1)//2 if check(mid): left = mid else: right = mid-1 print(right)
n,m = map(int,input().split()) # initialize the board # b是一个棋盘的差分数组 b = [[0]*(n+2) for i inrange(n+2)] # begin to run the instructions # 每一条指令都让区间内所有元素加一,最后看元素的奇偶性决定最终的棋子状态 for _ inrange(m): x1,y1,x2,y2 = map(int,input().split()) b[x1][y1] += 1 b[x2+1][y1] -= 1 b[x1][y2+1] -= 1 b[x2+1][y2+1] += 1 # 还原原数组,计算出结果 a = [[0]*(n+2) for i inrange(n+2)] for i inrange(1,n+1): for j inrange(1,n+1): a[i][j] = (a[i-1][j] + a[i][j-1] - a[i-1][j-1] + b[i][j]+2)%2 print(a[i][j],end = '') print()
三体人将对地球发起攻击。为了抵御攻击,地球人派出了 A×B×C 艘战舰,在太空中排成一个 A 层 B 行 C 列的立方体。
其中,第 i 层第 j 行第 k 列的战舰(记为战舰 (i,j,k))的生命值为 d(i,j,k)。三体人将会对地球发起 m 轮“立方体攻击”,每次攻击会对一个小立方体中的所有战舰都造成相同的伤害。具体地,第 t 轮攻击用 7 个参数 lat,rat,lbt,rbt,lct,rct,ht描述;
所有满足 i∈[lat,rat],j∈[lbt,rbt],k∈[lct,rct] 的战舰 (i,j,k) 会受到 ht 的伤害。
如果一个战舰累计受到的总伤害超过其防御力,那么这个战舰会爆炸。
地球指挥官希望你能告诉他,第一艘爆炸的战舰是在哪一轮攻击后爆炸的。
defcheck(times): # 检查经过times轮的攻击后是否存在爆炸的战舰、 global a,b,c,hits reduce = [[[0for i inrange(c+2)] for j inrange(b+2)] for k inrange(a+2)] for t inrange(times): la,ra,lb,rb,lc,rc,v = hits[t] reduce[la][lb][lc] += v reduce[la][lb][rc+1] -= v reduce[la][rb+1][lc] -= v reduce[ra+1][lb][lc] -= v reduce[ra+1][rb+1][lc] += v reduce[ra+1][lb][rc+1] += v reduce[la][rb+1][rc+1] += v reduce[ra+1][rb+1][rc+1] -= v # 根据差分数组还原出原数组,并和防御值进行比较 # 注意原坐标从1开始计数 for i inrange(1,a+1): for j inrange(1,b+1): for k inrange(1,c+1): # 将差分数组转换成其所对应的前缀和数组 # 容斥定理 reduce[i][j][k] += reduce[i-1][j][k]+reduce[i][j-1][k]+reduce[i][j][k-1]-reduce[i-1][j-1][k]-reduce[i-1][j][k-1]-reduce[i][j-1][k-1]+reduce[i-1][j-1][k-1] # 检查是否爆炸 if reduce[i][j][k] > d[(k-1)+c*((j-1)+b*(i-1))]: returnTrue returnFalse
a,b,c,m = map(int,input().split()) d = [int(i) for i ininput().split()] hits = [list(map(int,input().split())) for i inrange(m)] # binary search left = 1 right = m while left < right: mid = (left+right)//2 if check(mid): right = mid else: left = mid+1 print(left)