2018年第九屆藍橋杯省賽真題解題報告(Python版)-2

13 航班時間

提示:正則表達式

'''

標題:航班時間

【問題背景】
小h前往美國參加了藍橋杯國際賽。小h的女朋友發現小h上午十點出發,上午十二點到達美國,於是感嘆到“現在飛機飛得真快,兩小時就能到美國了”。

小h對超音速飛行感到十分恐懼。仔細觀察後發現飛機的起降時間都是當地時間。由於北京和美國東部有12小時時差,故飛機總共需要14小時的飛行時間。

不久後小h的女朋友去中東交換。小h並不知道中東與北京的時差。但是小h得到了女朋友來回航班的起降時間。小h想知道女朋友的航班飛行時間是多少。

【問題描述】
對於一個可能跨時區的航班,給定來回程的起降時間。假設飛機來回飛行時間相同,求飛機的飛行時間。

【輸入格式】
從標準輸入讀入數據。

一個輸入包含多組數據。

輸入第一行爲一個正整數T,表示輸入數據組數。

每組數據包含兩行,第一行爲去程的 起降 時間,第二行爲回程的 起降 時間。

起降時間的格式如下

h1:m1:s1 h2:m2:s2
或
h1:m1:s1 h3:m3:s3 (+1)
或
h1:m1:s1 h4:m4:s4 (+2)
表示該航班在當地時間h1時m1分s1秒起飛,

第一種格式表示在當地時間 當日 h2時m2分s2秒降落

第二種格式表示在當地時間 次日 h3時m3分s3秒降落。

第三種格式表示在當地時間 第三天 h4時m4分s4秒降落。

對於此題目中的所有以 h:m:s 形式給出的時間, 保證 ( 0<=h<=23, 0<=m,s<=59 ).

【輸出格式】
輸出到標準輸出。

對於每一組數據輸出一行一個時間hh:mm:ss,表示飛行時間爲hh小時mm分ss秒。

注意,當時間爲一位數時,要補齊前導零。如三小時四分五秒應寫爲03:04:05。

【樣例輸入】
3
17:48:19 21:57:24
11:05:18 15:14:23
17:21:07 00:31:46 (+1)
23:02:41 16:13:20 (+1)
10:19:19 20:41:24
22:19:04 16:41:09 (+1)

【樣例輸出】
04:09:05
12:10:39
14:22:05

【限制與約定】
保證輸入時間合法,飛行時間不超過24小時。

資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗  < 1000ms


請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。

'''
N = 0

import re

p1 = re.compile(r'(\d+):(\d+):(\d+) (\d+):(\d+):(\d+)')
p2 = re.compile(r'(\d+):(\d+):(\d+) (\d+):(\d+):(\d+) \(\+(\d)\)')


def getTime(s):
    '''

    :param s:
    :return: 兩個時間差,單位爲秒
    '''
    h1, m1, s1, h2, m2, s2, d = 0, 0, 0, 0, 0, 0, 0
    matchObj = p1.fullmatch(s)
    # 匹配第一種模式
    if matchObj:
        h1, m1, s1, h2, m2, s2 = (int(x) for x in matchObj.groups())
    # 匹配第二種模式
    else:
        matchObj = p2.fullmatch(s)
        h1, m1, s1, h2, m2, s2, d = (int(x) for x in matchObj.groups())

    return d * 24 * 3600 + h2 * 3600 + m2 * 60 + s2 - (h1 * 3600 + m1 * 60 + s1)


if __name__ == '__main__':
    N = int(input().strip())
    for i in range(N):
        t1 = getTime(input())
        t2 = getTime(input())
        t = (t1 + t2) // 2
        print('{:0>2d}:{:0>2d}:{:0>2d}'.format(t // 3600, t // 60 % 60, t % 60))

14 遞增三元組

提示:排序

'''

標題:遞增三元組

給定三個整數數組
A = [A1, A2, ... AN],
B = [B1, B2, ... BN],
C = [C1, C2, ... CN],
請你統計有多少個三元組(i, j, k) 滿足:

1. 1 <= i, j, k <= N
2. Ai < Bj < Ck

【輸入格式】
第一行包含一個整數N。
第二行包含N個整數A1, A2, ... AN。
第三行包含N個整數B1, B2, ... BN。
第四行包含N個整數C1, C2, ... CN。

對於30%的數據,1 <= N <= 100
對於60%的數據,1 <= N <= 1000
對於100%的數據,1 <= N <= 100000 0 <= Ai, Bi, Ci <= 100000

【輸出格式】
一個整數表示答案

【輸入樣例】
3
1 1 1
2 2 2
3 3 3

【輸出樣例】
27


資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗  < 1000ms
'''

if __name__ == '__main__':
    '''
    對三個數組排序
    以中間數組爲基準,在第一個數組中尋找比當前數小的數據個數p1
    在第三個數組中尋找比當前數小於等於的數據個數進而得到大於當前數的數據個數爲N-p2
    兩數相乘即得當前數爲中心的三元組的個數,累加到ans即可
    '''
    N = int(input().strip())
    data = [[int(x) for x in input().strip().split(' ')] for _ in range(3)]
    d0 = sorted(data[0])
    d1 = sorted(data[1])
    d2 = sorted(data[2])
    ans, p1, p2 = 0, 0, 0
    for j in range(N):
        while p1 < N and d0[p1] < d1[j]:
            p1 += 1
            if p1 == N:
                break
        while p2 < N and d2[p2] <= d1[j]:
            p2 += 1
            if p2 == N:
                break
        ans += p1 * (N - p2)
    print(ans)

15 次數差

提示:很簡單的計數

'''

標題:次數差

x星球有26只球隊,分別用a~z的26個字母代表。他們總是不停地比賽。
在某一賽段,哪個球隊獲勝了,就記錄下代表它的字母,這樣就形成一個長長的串。
國王總是詢問:獲勝次數最多的和獲勝次數最少的有多大差距?(當然,他不關心那些一次也沒獲勝的,認爲他們在怠工罷了)

輸入,一個串,表示球隊獲勝情況(保證串的長度<1000)

要求輸出一個數字,表示出現次數最多的字母比出現次數最少的字母多了多少次。

比如:
輸入:
abaabcaa

則程序應該輸出:
4

解釋:a出現5次,最多;c出現1次,最少。5-1=4

再比如:
輸入:
bbccccddaaaacccc

程序應該輸出:
6



資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗  < 1000ms


請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。

'''
from collections import defaultdict

if __name__ == '__main__':
    line = input()
    '''
    cnt = defaultdict(int)
    # 計數
    for x in line:
        cnt[x] += 1
    # 按值排序,返回2元組的列表
    sorted_cnt=sorted(cnt.items(), key=lambda item: item[1])
    print(sorted_cnt[-1][1] - sorted_cnt[0][1])
    '''

    from collections import Counter
    '''
    Counter是個好東西,專用於計數
    '''
    count = Counter(line).most_common()
    print(count[0][1] - count[-1][1])

16 三體攻擊

提示:比較複雜,要用三維差分並二分攻擊次數

'''

標題:三體攻擊

【題目描述】
三體人將對地球發起攻擊。爲了抵禦攻擊,地球人派出了 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 的傷害。如果一個戰艦累計受到的總傷害超過其防禦力,那麼這個戰艦會爆炸。

地球指揮官希望你能告訴他,第一艘爆炸的戰艦是在哪一輪攻擊後爆炸的。

【輸入格式】
從標準輸入讀入數據。
第一行包括 4 個正整數 A, B, C, m;
第二行包含 A × B × C 個整數,其中第 ((i − 1)×B + (j − 1)) × C + (k − 1)+1 個數爲 d(i, j, k);
第 3 到第 m + 2 行中,第 (t − 2) 行包含 7 個正整數 lat, rat, lbt, rbt, lct, rct, ht。

【輸出格式】
輸出到標準輸出。
輸出第一個爆炸的戰艦是在哪一輪攻擊後爆炸的。保證一定存在這樣的戰艦。

【樣例輸入】
2 2 2 3
1 1 1 1 1 1 1 1
1 2 1 2 1 1 1
1 1 1 2 1 2 1
1 1 1 1 1 1 2

【樣例輸出】
2

【樣例解釋】
在第 2 輪攻擊後,戰艦 (1,1,1) 總共受到了 2 點傷害,超出其防禦力導致爆炸。


【數據約定】
對於 10% 的數據,B = C = 1;
對於 20% 的數據,C = 1;
對於 40% 的數據,A × B × C, m ≤ 10, 000;
對於 70% 的數據,A, B, C ≤ 200;
對於所有數據,A × B × C ≤ 10^6, m ≤ 10^6, 0 ≤ d(i, j, k), ht ≤ 10^9。


資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗  < 3000ms


請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。

'''

# 思路:
# 1)範圍攻擊用差分記錄,這樣每次攻擊只需花O(1)的時間來記錄
# 2)二分攻擊次數,攻破了,就在下半區二分回覆血量,沒攻破就在上半區再二分繼續攻擊 O(logm)
# 3)每次檢查是否攻破,求差分前綴和求最終血量,再遍歷ABC個格子,看是否有血量小於0來判斷 O(ABC)

from copy import copy

a, b, c = 0, 0, 0


def getX(i, j, k):
    '''
    :param i:
    :param j:
    :param k:
    :return: 轉爲1維索引
    '''
    return ((i - 1) * b + j - 1) * c + k


def add(cc, i, j, k, h):
    '''
    修改ijk座標的差分數組的值
    :param cc:
    :param i:
    :param j:
    :param k:
    :param h:
    :return:
    '''
    if i < a and j < b and k < c:
        cc[getX(i, j, k)] += h


def op(cc, atk, f):
    '''
    :param cc: 差分數組
    :param atk: 元組,數據是一次攻擊的相關參數
    :param f: 1或者-1,代表攻擊還是回覆血量
    :return: void
    '''
    la, ra, lb, rb, lc, rc, h = atk
    h = h * f
    add(cc, la, lb, lc, h)
    add(cc, la, rb + 1, lc, -h)
    add(cc, la, lb, rc + 1, -h)
    add(cc, la, rb + 1, rc + 1, h)
    add(cc, ra + 1, lb, lc, -h)
    add(cc, ra + 1, rb + 1, lc, h)
    add(cc, ra + 1, lb, rc + 1, h)
    add(cc, ra + 1, rb + 1, rc + 1, -h)


def check(cc, d):
    '''
    三個維度累加,得差分數組的前綴和,就能得到每個點上的當前血量的變化量
    :param cc:
    :param d:
    :return:
    '''
    # 差分數組的前綴和,來自差分數組的複製
    _sum = copy(cc)
    for i in range(2, a):
        for j in range(1, b):
            for k in range(1, c):
                _sum[getX(i, j, k)] += _sum[getX(i - 1, j, k)]
    for i in range(1, a):
        for j in range(2, b):
            for k in range(1, c):
                _sum[getX(i, j, k)] += _sum[getX(i, j - 1, k)]
    for i in range(1, a):
        for j in range(1, b):
            for k in range(2, c):
                _sum[getX(i, j, k)] += _sum[getX(i, j, k - 1)]

    # 遍歷每個點,檢查變化量是否大於原始血量
    for i in range(1, a):
        for j in range(1, b):
            for k in range(1, c):
                index = getX(i, j, k)
                if _sum[index] > d[index]:
                    return True
    return False


if __name__ == '__main__':
    # import sys
    #
    # sys.stdin = open('/Users/zhengwei/data/in6.txt')
    A, B, C, m = (int(x) for x in input().strip().split(' '))
    a, b, c = A + 1, B + 1, C + 1
    _d = [int(x) for x in input().strip().split(' ')]  # 原始血量數據
    # 統一爲三維情況
    d = [0 for _ in range(a * b * c)]  # 原始血量(爲了便於從1開始,增加長寬高,可用ijk定位)
    index = 0
    for i in range(1, a):
        for j in range(1, b):
            for k in range(1, c):
                d[getX(i, j, k)] = _d[index]
                index += 1

    cc = [0 for _ in range(a * b * c)]  # 差分數組
    # 攻擊數據
    atk = [tuple()]  # 注意,下標從1開始,所以要佔位一個空的元組作爲0號元素
    for i in range(m):
        atk.append(tuple(int(x) for x in input().strip().split(' ')))
        # print(atk[i])

    # 二分攻擊次數
    l, r, lastMid = 1, m, 0
    while l < r:
        mid = (l + r) >> 1
        if lastMid < mid:  # 上一次攻擊沒有攻破,繼續攻擊
            for i in range(lastMid + 1, mid + 1):
                op(cc, atk[i], 1)  # 修改差分數組
        elif lastMid > mid:  # 上一次攻破了,恢復血量
            for i in range(mid + 1, lastMid + 1):
                op(cc, atk[i], -1)
        # 如果爆了,調整邊界
        if check(cc, d):
            r = mid
        else:
            l = mid + 1
        lastMid = mid
    print(r)

17 螺旋折線

提示:以右下角對角線上的點爲參照點(等差數列),測算給定的點到參照點要走的距離

'''
標題:螺旋折線

如圖p1.png所示的螺旋折線經過平面上所有整點恰好一次。
對於整點(X, Y),我們定義它到原點的距離dis(X, Y)是從原點到(X, Y)的螺旋折線段的長度。

例如dis(0, 1)=3, dis(-2, -1)=9

給出整點座標(X, Y),你能計算出dis(X, Y)嗎?

【輸入格式】
X和Y

對於40%的數據,-1000 <= X, Y <= 1000
對於70%的數據,-100000 <= X, Y <= 100000
對於100%的數據, -1000000000 <= X, Y <= 1000000000

【輸出格式】
輸出dis(X, Y)


【樣例輸入】
0 1

【樣例輸出】
3


資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗  < 1000ms


請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。
'''


def _sum(a0, n, d):
    return (2 * a0 + (n - 1) * d) * n // 2


if __name__ == '__main__':
    # 以右下角對角線上的點爲參照點,測算給定的點到參照點要走的距離
    X, Y = (int(i) for i in input().strip().split(' '))
    d, n = 0, 0  # 距離和第幾圈
    if Y > 0 and abs(X) <= Y:
        n = Y
        d = Y - X + 2 * Y
    elif X > 0 and abs(Y) <= X:
        n = X
        d = Y + X
    elif Y <= 0 and Y - 1 <= X <= -Y:
        n = -Y
        d = -(-Y - X)
    elif X < 0 and X + 1 <= Y <= -X:
        n = -X - 1
        d = -(Y - X - 1 - 2 * X - 1)
    print(_sum(1, 2 * n, 1) * 2 - d)

18 縮位求和

簡單題

'''
標題:縮位求和

在電子計算機普及以前,人們經常用一個粗略的方法來驗算四則運算是否正確。
比如:248 * 15 = 3720
把乘數和被乘數分別逐位求和,如果是多位數再逐位求和,直到是1位數,得
2 + 4 + 8 = 14 ==> 1 + 4 = 5;
1 + 5 = 6
5 * 6
而結果逐位求和爲 3
5 * 6 的結果逐位求和與3符合,說明正確的可能性很大!!(不能排除錯誤)

請你寫一個計算機程序,對給定的字符串逐位求和:
輸入爲一個由數字組成的串,表示n位數(n<1000);
輸出爲一位數,表示反覆逐位求和的結果。

例如:
輸入:
35379

程序應該輸出:
9

再例如:
輸入:
7583676109608471656473500295825

程序應該輸出:
1


資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗  < 1000ms


請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多餘內容。

'''

if __name__ == '__main__':
    s = input()
    while len(s) > 1:
        s = str(sum(int(x) for x in s))
    print(s)

19 全球變暖

提示:基本就是bfs的模板題

'''
標題:全球變暖

你有一張某海域NxN像素的照片,"."表示海洋、"#"表示陸地,如下所示:

.......
.##....
.##....
....##.
..####.
...###.
.......

其中"上下左右"四個方向上連在一起的一片陸地組成一座島嶼。例如上圖就有2座島嶼。

由於全球變暖導致了海面上升,科學家預測未來幾十年,島嶼邊緣一個像素的範圍會被海水淹沒。具體來說如果一塊陸地像素與海洋相鄰(上下左右四個相鄰像素中有海洋),它就會被淹沒。

例如上圖中的海域未來會變成如下樣子:

.......
.......
.......
.......
....#..
.......
.......

請你計算:依照科學家的預測,照片中有多少島嶼會被完全淹沒。

【輸入格式】
第一行包含一個整數N。  (1 <= N <= 1000)
以下N行N列代表一張海域照片。

照片保證第1行、第1列、第N行、第N列的像素都是海洋。

【輸出格式】
一個整數表示答案。


【輸入樣例】
7
.......
.##....
.##....
....##.
..####.
...###.
.......

【輸出樣例】
1



資源約定:
峯值內存消耗(含虛擬機) < 256M
CPU消耗  < 1000ms

'''


class Point(object):
    def __init__(self, i, j):
        self.i = i
        self.j = j


ans = 0
graph, mark = [], []

dx = (-1, 1, 0, 0)
dy = (0, 0, -1, 1)


def bfs(i, j):
    mark[i][j] = 1
    cntOfBlock, cntOfSwed = 0, 0 # 記錄塊的個數以及會被淹沒的塊的個數
    q, q_index = [], 0 # 隊列及隊列頭部的索引位置
    q.append(Point(i, j))
    while q_index != len(q):
        top = q[q_index]
        q_index += 1
        cntOfBlock += 1
        swed = False
        for k in range(4):  # 四個方向去探測
            nx, ny = top.i + dx[k], top.j + dy[k]
            if 0 <= nx < N and 0 <= ny < N:
                if graph[nx][ny] == '.':  # 會被淹沒
                    swed = True
                if graph[nx][ny] == '#' and mark[nx][ny] == 0:  # 鄰居中的#如果沒有被訪問,加入到隊列中
                    mark[nx][ny] = 1
                    q.append(Point(nx, ny))
        if swed:
            cntOfSwed += 1
    if cntOfBlock == cntOfSwed:
        return 1
    else:
        return 0


if __name__ == '__main__':
    '''
    bfs模板題
    '''
    N = int(input())
    mark = [[0] * N for _ in range(N)]
    for _ in range(N):
        graph.append(input())
    for i in range(N):
        for j in range(N):
            if graph[i][j] == '#' and mark[i][j] == 0:
                ans += bfs(i, j)
    print(ans)

20 日誌統計

提示:按時間排序,在時段內作id統計

'''
 標題:日誌統計

 小明維護着一個程序員論壇。現在他收集了一份"點贊"日誌,日誌共有N行。其中每一行的格式是:

 ts id

 表示在ts時刻編號id的帖子收到一個"贊"。

 現在小明想統計有哪些帖子曾經是"熱帖"。如果一個帖子曾在任意一個長度爲D的時間段內收到不少於K個贊,小明就認爲這個帖子曾是"熱帖"。

 具體來說,如果存在某個時刻T滿足該帖在[T, T+D)這段時間內(注意是左閉右開區間)收到不少於K個贊,該帖就曾是"熱帖"。

 給定日誌,請你幫助小明統計出所有曾是"熱帖"的帖子編號。

 【輸入格式】
 第一行包含三個整數N、D和K。
 以下N行每行一條日誌,包含兩個整數ts和id。

 對於50%的數據,1 <= K <= N <= 1000
 對於100%的數據,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000

 【輸出格式】
 按從小到大的順序輸出熱帖id。每個id一行。

 【輸入樣例】
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

 【輸出樣例】
 1
 3

 資源約定:
 峯值內存消耗(含虛擬機) < 256M
 CPU消耗  < 1000ms

'''


class record(object):
    def __init__(self, ts, td):
        self.ts = ts
        self.td = td

    def __eq__(self, other):
        return self.ts == other.ts

    def __lt__(self, other):
        return self.ts < other.ts

    def __str__(self):
        return f'{self.ts} {self.td}'


if __name__ == '__main__':
    import sys
    # sys.stdin = open('/Users/zhengwei/data/in8.txt')
    N, D, K = (int(x) for x in input().split(' '))
    records, ans = [], set()
    for i in range(N):
        ts, td = (int(x) for x in input().split(' '))
        records.append(record(ts, td))
    # 按照時間排序
    sorted_records = sorted(records)

    from collections import defaultdict

    id_cnt = defaultdict(int)
    j = 0
    for i in range(N):
        while j < N and sorted_records[j].ts - sorted_records[i].ts < D:
            j__td = sorted_records[j].td
            id_cnt[j__td] += 1  # 計數+1
            if id_cnt[j__td] >= K:
                ans.add(j__td)
            j += 1
        id_cnt[sorted_records[i].td] -= 1  # i的id的計數-1

    # 排序id並輸出
    for id in sorted(ans):
        print(id)

21 等腰三角形

簡單題

'''
標題:等腰三角形

本題目要求你在控制檯輸出一個由數字組成的等腰三角形。
具體的步驟是:
1. 先用1,2,3,...的自然數拼一個足夠長的串
2. 用這個串填充三角形的三條邊。從上方頂點開始,逆時針填充。
比如,當三角形高度是8時:

       1
      2 1
     3   8
    4     1
   5       7
  6         1
 7           6
891011121314151

顯示不正確時,參看:p1.png

輸入,一個正整數n(3<n<300),表示三角形的高度
輸出,用數字填充的等腰三角形。

爲了便於測評,我們要求空格一律用"."代替。

例如:
輸入:
5

程序應該輸出:
....1
...2.1
..3...2
.4.....1
567891011

再例如:
輸入:
10

程序應該輸出:
.........1
........2.2
.......3...2
......4.....2
.....5.......1
....6.........2
...7...........0
..8.............2
.9...............9
1011121314151617181

再例如:
輸入:
15

程序應該輸出:

..............1
.............2.3
............3...2
...........4.....3
..........5.......1
.........6.........3
........7...........0
.......8.............3
......9...............9
.....1.................2
....0...................8
...1.....................2
..1.......................7
.1.........................2
21314151617181920212223242526

'''

if __name__ == '__main__':
    n = int(input())
    # 用於填充三角形的字符的個數——字符串的長度
    length = 4 * (n - 1)
    # 遞增數字和實際長度
    num, cur_len = 1, 0
    str_arr = []
    while cur_len < length:
        str1 = str(num)
        str_arr.append(str1)
        num += 1
        cur_len += len(str1)
    s = ''.join(str_arr)
    # 字符串構建完畢
    # 第一行
    for _ in range(n - 1):
        print('.', end='')
    print(s[0])
    # 中間行
    for i in range(1,n - 1):
        for j in range(n - i - 1):
            print('.', end='')
        print(s[i], end='')
        for j in range(2 * i - 1):
            print('.', end='')
        print(s[length - i])
    # 最後一行
    for i in range(n - 1, length - (n - 2)):
        print(s[i], end='')
    print()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章