Lanqiao Cup 2021 Provincial Competition Python

Lanqiao Cup 2021 Provincial Competition Python

I have to say that 2021 is more difficult than 2020

1.Card

insert image description here

Obviously, the first thing to lose must be 1 or 0. We just need to count who will consume 2022 1 or 0.

if __name__ == '__main__':
    res1 = 0
    res0 = 0
    for i in range(1,100000):
        i = str(i)
        res1 += i.count('1')
        res0 += i.count('0')
        if res1 == 2022 or res0 == 2022 : 
            break
    print(int(i)-1)

# 3181

2. Straight line

insert image description here

Two-point formula (y1-y2)X + (x2-x1)Y + (x1 y2-x2 y1) = 0

Then we just need to traverse every two points, and then add the different ones to our set.

(y1-y2) * x +(x2-x1) * y +( x1 * y2 - x2 * y1)=0 Two-point equation

def gcd(a,b):
    if b == 0: return a
    else: return gcd(b,a%b)
if __name__ == '__main__':
    dian = []
    for i in range(20):
        for j in range(21):
            dian.append((i,j))
    res = set()
    for i in range(len(dian) - 1):
        x1,y1 = dian[i]
        for j in range(i+1,len(dian)):
            x2,y2 = dian[j]
            A,B,C = y2-y1,x2-x1,x1*y2-x2*y1
            k = gcd(gcd(A,B),C)  # 求三个数的最大公约数

            res.add((A/k,B/k,C/k))
            
    print(len(res))

3. Placement of goods

insert image description here

First of all, we can see that he must be able to get rid of all his factors. Preprocess it first and then traverse it

One thing to note is that if you preprocess his factors from 1 to n, it will be very slow, so we can only process sqrt(n)

import math
yin = []
n = 2021041820210418
# for i in range(1,n+1):  # 太慢了
#     if n % i == 0:
#         yin.append(i)
for i in range(1,int(math.sqrt(n) + 1)):
    if n % i == 0:
        yin.append(i)
        yin.append(n/i)

print('over')


res = 0
for i in yin:
    for j in yin:
        for k in yin:
            if i * k * j  == n:
                res += 1
print(res)

4.Path

insert image description here

A very simple dynamic programming problem. The distance from a point to 1 is equal to the distance from any of the 21 previous points to 1 plus the distance from that point to it. We only need to find the minimum value by traversing the previous 21 points. .

In this way, layer by layer, it will be the smallest, and it will be the smallest in the end.

def gcd(a,b):
    if b == 0: return a
    return gcd(b,a%b)
def gbs(a,b):
    return a*b//gcd(a,b)  
inf = 1e9
dp = [inf] * 2022  # dp表示到1的距离
for i in range(1,23):
    dp[i] = i

for i in range(23,2022):
    for j in range(1,22):
        dp[i] = min(dp[i],dp[i-j] + gbs(i,i-j)) # 后面的到1的距离等于前面21中的一个到1的距离加上前面21个中一个到他的距离
print(dp[2021])

PS: It seems that there is a function for finding the greatest common divisor in the math library. Just use it next time instead of defining it yourself. I am afraid that people will write it wrong due to slippery fingers.

5. Loop calculation

insert image description here

You see there are only 21 floors in total. We can use binary to represent it. For example, status 11101 means that we have gone to floors 1, 3, 4, and 5.

Set a dp, dp[i][j] represents the total number of people who can reach j in state i. If you look at this state, for example, i = 11101, j = 3, it is the total number of people who can reach j+1 = 4th floor. Quantity (why +1, because we use j = 0 to indicate that we have reached the first floor, and later we use i >> j & 1 to indicate whether we can reach this floor, so it is defined as j+1, if we want j If you arrive at the J floor, I need to open an extra seat, which will be bigger)

So how do we calculate the number of the fourth building? Looking at this status 11101, we find that it can have 1, 3, and 5 buildings to walk, then we can just traverse these three buildings, that is, to reach the fourth building The i of the building becomes 0, and then the remaining three buildings are reached.

Assume that k is traversed, dp[i][j] += dp[i - (1<<j)][k]

This state transfer is correct, because every time he uses i, it is smaller than him. It must have been traversed before, and there will be no leakage.

 import math
n = 21
m = 1<<21
dp = [[0] * n  for _ in range(m+1)] # do[i][j]表示状态i到到达j的总数量
g =[[0]*n for _ in range(n)]  # g[i][j] 表示I能到J


for i in range(1,n+1):
    for j in range(1,n+1):
        if math.gcd(i,j) == 1: 
            g[i-1][j-1] = 1   
dp[1][0] = 1
# 如果要刚好dp[i][j] 表示第i个状态到第j个楼的话,要开22位的二进制,会更慢.所以我们j就表示J+1楼
for i in range(1,m):
    for j in range(n):
        if i >> j & 1:  # 判断j+1楼是否在里面
            for k in range(n):
                if i - (1 << j) >> k & 1 and g[k][j] == 1: #找到符合条件的k
                    dp[i][j] += dp[i - (1 << j)][k]

print(sum(dp[m-1]) - dp[m-1][0])  # 最后就是状态011111111111(21个1)到达不是1楼的就好了,因为每个楼都可以去1楼

6. Time display

insert image description here

First find the number of milliseconds in that day, then find the number of hours, and so on, the total number of milliseconds - the number of milliseconds in the hour = the number of minutes + the remaining milliseconds minus the hour and minute

n = int(input())
n = n%(24 * 60 * 60 * 1000) # 抛去前面N天的,剩下当天的毫秒数
hour = n // (60 * 60 *1000)
mins = (n - hour*60*60*1000) // (60 * 1000)
scent = (n - hour * 60 * 60 *1000 - mins * 60 * 1000) // 1000
print('%02d'%hour,end = ':')
print('%02d'%mins,end = ':')
print('%02d'%scent,end = '')

7. Yang Hui Triangle

insert image description here

At the beginning of this question, I only wrote one with high time complexity. It should be able to get the previous points. It is easier to understand, so you can take a look first.

 if __name__ == '__main__':
     n = int(input())
     if n == 1: print(1)
     res = 3 # 已经计算的个数
     li,l = [1,2],3  # 第三行的一半元素和行数
     while n not in li:
         res += len(li)*2 - l % 2
         li = [1] + [li[i] + li[i+1] for i in range(len(li) - 1)] + ([li[-1]*2] if l % 2 == 0 else []) 
         l += 1
     print(res + li.index(n) + 1)

Just go through it line by line until we find what we need.

The second one is that I think mine is too slow. Looking at the big guys, I have to say that it is too strong. .

Reference for ideas: (156 messages) Preparing for the Lanqiao Cup past test questions: Yang Hui’s detailed explanation of Python for Group B of the Triangle Provincial Competition_m0_62277756’s blog-CSDN blog

But there are still some things that seem to be wrong. Let me point them out here first. If they are wrong, you can tell me in the comment area. . (Of course the code is correct) When traversing the oblique lines, the boss said to find C(2i,N) from C(2i,i). Is there any answer for us, but I checked that it should be from C(2i, i) to C(N,i) because C(N,1) is definitely the answer we want. C(N,i) will be greater than him, because I thought about this for a long time. . I hope everyone can notice this when watching. It's really amazing to find this rule.

def c(a,b):
    res = 1
    i,j = a,1
    while j<=b:
        res = res * i / j
        i -= 1
        j += 1
    return int(res)

def find(j,n):  # 在第j斜行找到n的位置
    l,r = 2*j,n # C(a,j)的a最小是2*j 最大是n,因为C(n,1)够了已经
    while l <= r:
        mid = (l+r)//2
        if c(mid,j) == n:
            print(int(mid*(mid+1)/2) + j + 1) # j+1不能在里面,否则会被忽略
            return True
        elif c(mid,j) > n:
            r = mid - 1
        else: l = mid + 1
    return False

if __name__ == '__main__':
    N = int(input())
    for i in range(16,-1,-1):
        if find(i,N): break

8. Left child, right brother

0

In fact, I feel that this question has nothing to do with the left child and right brother we learned. You just need to turn your brothers into your right child, and then turn your child into your left child. Then we can first deduce that if you have 3 children, then the height of the tree with you as the root is the maximum value of the tree height of 3+3 children. ### Because you can turn one of the three children into a left child, and then leave two of them as the right child of that left child, and then leave one of them as the right child of the left child's right child (draw A picture will be much better, I suggest to draw a picture) Then we only need to find the tree with the tallest three children, let him be the last child, then the overall tree will definitely be the tallest, and it will be equal to the maximum tree height of 3+3 children Value, we dfs search just fine.

The height without children is 0

ans = 0 
# f[u]以u结点为根的树的最大高度是u的子节点数量 + 各个子树的最大高度
# 其实就是看子树有多少个孩子,递归下去
def dfs(u): # 
    global ans
    tot = len(s[u])
    f[u] = tot
    res = 0
    for i in range(tot):
        v = s[u][i]
        m = dfs(v)
        res = max(res,m)
    f[u] += res
    return f[u]
        

if __name__ == '__main__':
    n = int(input())
    s = [[] for i in range(n+1)]
    for i in range(n-1):
        s[int(input())].append(i+2) 
    # 输入 5 1 1 1 2  那就是 s[1] = [2,3,4] 表示 2,3,4是父节点是1
    f = [0]*(n+1)
    print(dfs(1))

9. XOR sequence

insert image description here

This question is a bit difficult. I feel that this is the best I can do.

You can think about it, XOR, the highest bit of all numbers in binary is 11, if the 11th bit is only one, then the first hand must win, he just needs to take this, and the rest No matter how XOR is performed, his highest position will not change.

How about 3 in the 11th place? It depends on how many are left. Think about it this way, assuming there are 4 numbers in total, then the highest digit of the remaining number is not 1, right? In this way, the first mover must lose. Because if you take the one with the highest bit of 1 first, and I take the one with the highest bit that is not 1, you can only let me XOR the highest bit is 1 or you XOR the highest bit is 1, if you let me XOR The highest bit is 1, then I will let you XOR the highest bit to be 1, so that my highest bit is 1 and your highest bit is 0, then if you remove the one with the highest bit of 0 first, I take one whose highest digit is 1, and the highest digits of the remaining two numbers are both 1 (the highest digit here is the highest digit of all numbers), if you XOR drop my highest digit, I will take it again, If you want to use the highest bit to XOR your own number, then I will XOR you next time and you will still lose.

But if there are even numbers left, it will be different. I will take the one whose highest digit is 1 first. If you take the remaining highest digit that is not 1, I will also take one. Because it is an even number, I will definitely be able to take one. Take one, then in the end there will be an even number of highest bits that are 1 (because I took one at the beginning), then yes, you XOR me, I will take another one, you XOR yourself, I will XOR you, In the end, your highest position will definitely not be 1, and my highest position will be 1.

Is there an even number of 11th digits? If there is no way, then we have to look at the next highest position, which is No. 10.

if __name__ == '__main__':
    t = int(input())

    for i in range(t):
        sum = 0
        max2 = 0
        list1 = [int(x) for x in input().split()]
        for i in range(1,len(list1)):
            sum ^= list1[i]
            max2 = max(max2,list1[i])  # 顺便记录下来最大的先 
        if sum == 0 :
            print(0)
            continue
        high = 1
        while high < max2:
            high = high<<1  # 找到最大的那个的最高位是多少
        while high > 0:
            temp = 0
            for i in list1[1:]:
                if i & high != 0: # 最高位和high相同
                    temp += 1
            if temp == 1:
                print(1)
                break # 先手赢
            if temp %2 == 1: # 如果有奇数个最高位为1,那么就要看剩下的有几个
                if list1[0] % 2 == 1:  # n如果是奇数 减去奇数个最高位相同的,剩下的就是偶数个
                    print(1)
                    break # 除去最高位一样的那些,剩下的有偶数,就先手赢
                else: 
                    print(-1)
                    break # 否则后手赢
            if temp %2 == 0:  #如果最高位有偶数位,则顺延到下一位
                high = high >> 1

PS: I feel like what I said is a bit confusing. If you don’t know how, you can discuss it with me.

10. Bracket sequence

insert image description here

I really don’t know how to solve this question. It took me a long time to figure it out. You can take a look at the Da Xuecai at Station B. . . I also read about him, but there are a few points I think I can talk about, which may cause some confusion during the learning process.

The first is the state transition equation. dp[i][j] represents the number of options in the first i sequence where there are j more left brackets than right brackets.

Here we first consider adding the left bracket. If the position on the i-th sequence is the right bracket, dp[i][j] = dp[i-1][j+1] + dp[i-1][j] + … + dp[i-1][0]

What does this mean? It means that you have a right bracket in the i-th sequence. Then we can choose to add a left bracket before your right bracket, right? If I choose to add 1, you will have to leave the first i sequence. There are j more brackets than right brackets, so does the first i-1 sequence require j more left brackets than right brackets? Because I added a left bracket, but the i-th one is a right bracket, these two cancel out. If I choose to add 3 left brackets in front of this right bracket, then the number of options will be equal to dp[i-1][j-2]. Think about it, in the previous i-1 sequences, there are j more left brackets than right brackets. -2, and then added three left brackets and one right bracket, is it dp[i][j]?

If the i-th position is a left parenthesis, then nothing needs to be done.

dp[i][j] = dp[i-1][j-1] If a left bracket is added here, it will be equal to the previous i-1 sequence. There are j-1 more left brackets than right brackets.

Then there is the question that I have never been able to figure out. Why is the final solution for outputting left brackets not to directly output dp[n][0], but in the first n sequences, there are 0 more left brackets than right brackets. I feel like it is me later. The idea is too happy, if there is a sequence ((()), where can we add the least parentheses? The best choice is to add right parentheses instead of left parentheses, so for left parentheses, Finally, what we have to choose is dp[4][2], not dp[4][0]. Only under perfect circumstances will dp[n][0] appear, such as ())), so It must be dp[n][0]. To sum up, the dp[n][i] we output, i is the smallest, must be the number of solutions we want to add the minimum number of left brackets.

For right brackets, just reverse the order and change the left and right brackets to each other, and continue to use the left bracket template.

def func():
    dp = [[0] * (n+2) for _ in range(n+2)] # dp[i][j] 表示前i个序列,左括号比右括号多j个的方案数
    dp[0][0] = 1
    for i in range(1,n+1):
        if s[i-1] == '(':
            for j in range(1,n+1):
                dp[i][j] = dp[i-1][j-1]
        else:
            dp[i][0] = (dp[i - 1][0] + dp[i-1][1]) % mod
            for j in range(1,n+1):
                dp[i][j] = (dp[i][j-1] + dp[i-1][j+1]) % mod # 0特判是因为会出界
    for i in range(n+1):
        if dp[n][i]:  #找前n个中左括号比右括号多的数最少,表示我们添加的也最少
            return dp[n][i]
    return -1
if __name__ == '__main__':
    s = list(input())
    n = len(s)
    mod = 1e9 + 7
    left = func()
    s.reverse()  # 从左往右看是填左括号,右往左是填右括号
    # 但是因为我们func是按左括号写的,所以还需要将左括号和右括号对调一下,这样我们就不用重新写一个函数
    for i in range(n):
        if s[i] == ')':
            s[i] = '('
        else:
            s[i] = ')'
    right = func()
    print(int(left*right % mod))

I feel that this question is still very difficult and I will definitely not be able to do it in the exam room. . . Come on, everybody

Guess you like

Origin blog.csdn.net/abc1234564546/article/details/128769308