第十四届蓝桥杯大赛软件组省赛 Python大学A组 个人暴力题解

Posted NEFU AB-IN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十四届蓝桥杯大赛软件组省赛 Python大学A组 个人暴力题解相关的知识,希望对你有一定的参考价值。

Powered by:NEFU AB-IN

文章目录

博主个人的暴力题解,基本很少是正解,求轻喷

Python大学A组 个人暴力题解

  • 试题 A: 特殊日期

    • 题意

    • 思路

      模拟即可,本身想用Python自带的datetime库,结果发现年不能开那么大,就直接手写了

    • 代码

      '''
      Author: NEFU AB-IN
      Date: 2023-04-08 14:15:52
      FilePath: \\Vscode\\ACM\\LanQiao\\2023PythonA\\a.py
      LastEditTime: 2023-04-08 14:19:47
      '''
      # AB-IN AK Lanqiao !!
      # http://222.27.161.91/home.page
      # aR7H4tDF
      import sys, math
      from collections import Counter, deque, defaultdict
      from bisect import bisect_left, bisect_right
      from heapq import heappop, heappush, heapify
      from typing import *
      from datetime import datetime, timedelta
      
      N = int(1e6 + 10)
      INF = int(2e9)
      
      sys.setrecursionlimit(INF)
      read = lambda: map(int, input().split())
      
      
      class sa:
          def __init__(self, y, m, d):
              self.y = y
              self.m = m
              self.d = d
      
          def __lt__(self, x):
              pass
      
      
      # ---------------divrsion line ----------------
      
      # t1 = datetime(2000, 1, 1)
      # t2 = datetime(2000, 1, 2)
      
      # ans = 0
      # while True:
      #     if t1.year % t1.month == 0 and t1.year % t1.day == 0:
      #         ans += 1
      #     t1 = t1 + timedelta(days=1)
      #     if t1 == t2:
      #         break
      # print(ans)
      
      mouths = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
      
      
      def func(t1):
          y, m, d = t1.y, t1.m, t1.d
          if (y % 4 == 0 and y % 100) or (y % 400 == 0):
              mouths[2] = 29
          else:
          	mouths[2] = 28
          d += 1
          if d > mouths[m]:
              d = 1
              m += 1
          if m > 12:
              m = 1
              y += 1
          return sa(y, m, d)
      
      
      t1 = sa(2000, 1, 1)
      t2 = sa(2000000, 1, 2)
      
      ans = 0
      while True:
          if t1.y % t1.m == 0 and t1.y % t1.d == 0:
              ans += 1
          t1 = func(t1)
          if t1.y == t2.y and t1.m == t2.m and t1.d == t2.d:
              break
      print(ans)
      
      # 35813063
      
  • 试题 B: 分糖果

    • 题意

    • 思路

      DFS爆搜即可

    • 代码

      # AB-IN AK Lanqiao !!
      import sys, math
      from collections import Counter, deque, defaultdict
      from bisect import bisect_left, bisect_right
      from heapq import heappop, heappush, heapify
      from typing import *
      from datetime import datetime, timedelta
      
      N = int(1e6 + 10)
      INF = int(2e9)
      
      sys.setrecursionlimit(INF)
      read = lambda : map(int, input().split())
      
      class sa:
          def __init__(self, x, y):
              self.x = x
              self.y = y
          def __lt__(self, x):
              pass
      
      # ---------------divrsion line ----------------
      # 两种糖果分别有 9 个和 16 个,要全部分给 7 个小朋友,每个小朋友得到
      # 的糖果总数最少为 2 个最多为 5 个,问有多少种不同的分法。
      
      ans = 0
      def dfs(sum1, sum2, cnt):
          global ans
          if sum1 < 0 or sum2 < 0:
              return
          if cnt == 8:
              if sum1 == 0 and sum2 == 0:
                  ans += 1
              return
          for i in range(2, 6):
              dfs(sum1 - i, sum2, cnt + 1)
          for i in range(2, 6):
              dfs(sum1, sum2 - i, cnt + 1)
          for i in range(2, 6):
              for j in range(2, 6):
                  if i + j >= 2 and i + j <= 5:
                      dfs(sum1 - i, sum2 - j, cnt + 1)
      
      dfs(9, 16, 1)
      print(ans)
      
      # 148540
      
  • 试题 C: 三国游戏

    • 题意

    • 思路

      直接没思路,一看到数据范围瞬间怂了,脑子里想的只有暴力,这个题是留到最后写的,就写了个最差的二进制枚举

    • 代码

      # AB-IN AK Lanqiao !!
      import sys, math
      from collections import Counter, deque, defaultdict
      from bisect import bisect_left, bisect_right
      from heapq import heappop, heappush, heapify
      from typing import *
      from datetime import datetime, timedelta
      
      N = int(1e6 + 10)
      INF = int(2e9)
      
      sys.setrecursionlimit(INF)
      read = lambda : map(int, input().split())
      
      class sa:
          def __init__(self, x, y):
              self.x = x
              self.y = y
          def __lt__(self, x):
              pass
      
      # ---------------divrsion line ----------------
      # 最差方法 二进制枚举
      
      n, = read()
      a = list(read())
      b = list(read())
      c = list(read())
      ans = 0
      
      for i in range(1 << n):
          A, B, C, cnt = 0, 0, 0, 0
          for j in range(n):
              if i & 1 << j:
                  A += a[j]
                  B += b[j]
                  C += c[j]
                  cnt += 1
          if A > B + C or B > A + C or C > A + B:
              ans = max(ans, cnt)
      
      print(ans if ans != 0 else -1)
      
  • 试题 D: 平均

    • 题意

    • 思路

      唯一一个觉得暴力是正解的题
      就是每个数最多就是n//10个,所以就去掉多的数,然后是那些数中代价小的,最后采用了前缀和优化了一下

    • 代码

      # AB-IN AK Lanqiao !!
      import sys, math
      from collections import Counter, deque, defaultdict
      from bisect import bisect_left, bisect_right
      from heapq import heappop, heappush, heapify
      from typing import *
      from datetime import datetime, timedelta
      
      N = int(1e6 + 10)
      INF = int(2e9)
      
      sys.setrecursionlimit(INF)
      read = lambda : map(int, input().split())
      
      class sa:
         def __init__(self, a, b):
             self.a = a
             self.b = b
         def __lt__(self, t):
             if self.a != t.a:
                 return self.a < t.a
             return self.b < t.b
      
      # ---------------divrsion line ----------------
      
      n, = read()
      lst = [[] for _ in range(10)]
      
      for i in range(n):
         a, b = read()
         lst[a].append(b)
      
      for i in range(10):
         lst[i].sort()
         lst[i] = [0, *lst[i]]
         # 前缀和
         for j in range(1, len(lst[i])):
             lst[i][j] += lst[i][j - 1]
      
      # 保留的个数
      k = n // 10
      
      ans = 0
      for i in range(10):
         l = len(lst[i]) - 1
         if l > k:
             ans += (lst[i][l - k])
      
      print(ans)
      
  • 试题 E: 翻转

    • 题意

    • 思路

      BFS暴力,不会剪枝,剪枝想了一种,但是没有证明正确性,所以就没有采用

    • 代码

      # AB-IN AK Lanqiao !!
      import sys, math
      from collections import Counter, deque, defaultdict
      from bisect import bisect_left, bisect_right
      from heapq import heappop, heappush, heapify
      from typing import *
      from datetime import datetime, timedelta
      
      N = int(1e6 + 10)
      INF = int(2e9)
      
      sys.setrecursionlimit(INF)
      read = lambda : map(int, input().split())
      
      class sa:
          def __init__(self, s, step):
              self.s = s
              self.step = step
          def __lt__(self, x):
              pass
      
      # ---------------divrsion line ----------------
      # BFS暴力 不会剪枝 没证明剪枝一定正确
      
      def solve():
          t = input()
          s = input()
      
          t = " " + t
          s = " " + s
      
          if t[1] != s[1] or t[-1] != s[-1]:
              return -1
      
          q = deque()
          q.appendleft(sa(s, 0))
          while len(q):
              tp = q.pop()
              s, step = tp.s, tp.step
              if s == t:
                  return step
              for i in range(2, len(s) - 1):
                  if s[i] == '0' and s[i - 1] == '1' and s[i + 1] == '1':
                      g = s[:i - 1] + "111" + s[i + 2:]
                      if g == t:
                          return step + 1
                      q.appendleft(sa(g, step + 1))
                  if s[i] == '1' and s[i - 1] == '0' and s[i + 1] == '0':
                      g = s[:i - 1] + "000" + s[i + 2:]
                      if g == t:
                          return step + 1
                      q.appendleft(sa(g, step + 1))
          return -1
      
      
      T, = read()
      for _ in range(T):
          print(solve())
      
  • 试题 F: 子矩阵

    • 题意

    • 思路

      这版是直接暴力做的
      考试最后写了一点线段树优化,只不过只维护了行和列的最小值和最大值,但感觉Python写的线段树也优化不了多少

    • 代码

      # AB-IN AK Lanqiao !!
      import sys, math
      from collections import Counter, deque, defaultdict
      from bisect import bisect_left, bisect_right
      from heapq import heappop, heappush, heapify
      from typing import *
      from datetime import datetime, timedelta
      
      N = int(1e3 + 10)
      MOD = 998244353
      INF = int(2e9)
      
      sys.setrecursionlimit(INF)
      read = lambda : map(int, input().split())
      
      class sa:
          def __init__(self, x, y):
              self.x = x
              self.y = y
          def __lt__(self, x):
              pass
      
      # ---------------divrsion line ----------------
      # RMQ 问题 可写ST表 但我忘了...
      # 暴力!
      g = [[0] * N for _ in range(N)]
      n, m, a, b = read()
      
      def func(t1, t2):
          mn, mx = INF, 0
          for i in range(t1.x, t2.x + 1):
              for j in range(t1.y, t2.y + 1):
                  mn = min(mn, g[i][j])
                  mx = max(mx, g[i][j])
          return mx * mn % MOD
      
      for i in range(1, n + 1):
          g[i][1:] = read()
      
      ans = 0
      for i in range(1, n + 1):
          for j in range(1, m + 1):
              t1 = sa(i, j)
              t2 = sa(i + a - 1, j + b - 1)
              if i + a - 1 > n or j + b - 1 > m:
                  continue
              ans = (ans + func(t1, t2)) % MOD 
      
      print(ans)
      
  • 试题 G: 阶乘的和

    • 题意

    • 思路

      还是暴力,思路就是可以把共因子都提出来,剩下的加和,从提出来的共同的因子的最大值开始,让加和除以它,直到不能除了,就是答案
      其中,用哈希表记录用过的阶乘值,预处理一些阶乘值

    • 代码

      # AB-IN AK Lanqiao !!
      import sys, math
      from collections import Counter, deque, defaultdict
      from bisect import bisect_left问题描述 
      

      对于一个长度为 n 的 01 串 S = x 1 x 2 x 3 . . . x n S = x_1 x_2 x_3 ... x_n S=x1x2x3...xn,香农信息熵的定义为 H ( S ) = − ∑ 1 n p ( x i ) l o g 2 ( p ( x i ) ) H(S ) = − \\textstyle \\sum_1^n p(x_i)log_2 (p(x_i)) H(S)=1np(xi)log2(p(xi)),其中 p ( 0 ) p(0) p(0), p ( 1 ) (1) (1) 表示在这个 01 01 01 串中 0 0 0 1 1 1 出现的占比。比如,对于 S = 100 S = 100 S=100 来说,信息熵 H ( S ) = − 1 3 l o g 2 ( 1 3 ) − 2 3 l o g 2 ( 2 3 ) − 2 3 l o g 2 ( 2 3 ) = 1.3083 H(S ) = − \\frac13 log_2 ( \\frac13 ) − \\frac23 log_2( \\frac23 ) − \\frac23 log_2 ( \\frac23 ) = 1.3083 H(S)=31log2(31)32log2(32)32log2(32)=1.3083。对于一个长度为 23333333 23333333 23333333 01 01 01 串,如果其信息熵为 11625907.5798 11625907.5798 11625907.5798,且 0 0 0 出现次数比 1 1 1 少,那么这个 01 01 01 串中 0 0 0 出现了多少次?

      思路

      我们先来看这个 h ( s ) h(s) h(s) 的定义,然后先把 h ( s ) h(s) h(s) 这个函数写出来。

      我们看这个 100 100 100 的例子:一共有 1 个 1,2 个 0, h ( s ) h(s) h(s) 也是由 1 个 − 1 3 l o g 2 ( 1 3 ) − \\frac13 log_2 ( \\frac13 ) 31log2(31) 和 2 个 − 2 3 l o g 2 ( 2 3 ) − \\frac23 log_2( \\frac23 ) 32log2(32) 构成,再根据公式,我们可以推测:如果有 n 个 0,m 个 1,那么 h ( s ) h(s) h(s) 应该是由 n 个 p ( 0 ) l o g 2 ( p ( 0 ) ) p(0)log_2(p(0)) p(0)log2(p(0)) 构成,同时,由 m 个 p ( 1 ) l o g 2 ( p ( 1 ) ) p(1)log_2(p(1)) p(1)log2(p(1)) 构成。 p ( 0 ) p(0) p(0) 表示 0 出现的占比, p ( 0 ) = n n + m p(0) = \\fracnn + m p(0)=n+mn p ( 1 ) = m n + m p(1) = \\fracmn + m p(1)=n+mm。所以我们可以设一个函数,用来求解 h ( s ) h (s) h(s)

      #include <iostream>
      #include <cstring>
      #include <algorithm>
      
      using namespace std;
      
      int gcd(int a, int b) 
      	return b ? gcd(b, a % b) : a;
      
      
      // p0 表示 '0' 出现的次数;p1表示 '1' 出现的次数
      double h(int p0, int p1) 
      	// 需要将 3/6 化简成 1/2 这样的形式,简化运算的时间
      	// 将分子和分母共同除以它们的最大公因数即可。
      	int t0 = p0, t1 = p1;
      	// 获取最大公因数
      	int t = gcd(t0, t1);
      	// 化简
      	t0 /= t, t1 /= t;
      	// 获取总数
      	double t2 = t0 + t1;
      	// 返回的答案
      	double res = 0;
      	// 套入公式
      	res -= p0 * (t0 / t2) * (log2(t0) - log2(t2));
      	res -= p1 * (t1 / t2) * (log2(t1) - log2(t2));
      	return res;
      
      
      int main () 
      	// 100 由 2个0 和 1个1 组成,代入函数以验证函数的正确性
      	cout << h(2, 1) << endl;
      	
      	return 0;
      
      
      

      可得运行结果:

      1.30827
      

      与题目中的结果一致,说明我们写的代码是正确的。

      接下来我们就应该来求这个题目的答案了。

      我们先来看看这个函数的性质:我们多求几组数字。我们以长度为 10 的所有 01 串来看:

      int main () 
      	cout << h(9, 1) << endl;
      	cout << h(8, 2) << endl;
      	cout << h(7, 3) << endl;
      	cout << h(6, 4) << endl;
      	cout << h(5, 5) << endl;
      	cout << h(4, 6) << endl;
      	cout << h(3, 7) << endl;
      	cout << h(2, 8) << endl;
      	cout << h(1, 9) << endl;
      	return 0;
      
      

      可得运行结果:

      1.56342
      2.98911
      4.08468
      4.76816
      5
      4.76816
      4.08468
      2.98911
      1.56342
      

      我们可以发现:

      1. h ( s ) h(s) h(s) 关于 5 对称
      2. 在对称轴的一侧, h ( s ) h(s) h(s) 的值单调

      由于题目中说明:且 0 出现次数比 1 少 ,所以,0 的个数一定小于总数的一半,所以 0 的数量越多,熵越大。我们知道了这个性质以后,可以采用二分的方法,将 0 的数量二分出来。

      int main () 
      	// 0 的数量最小是 1, 最大是 (23333333 + 1) / 2 (总数的一半)
      	int l = 1, r = (23333333 + 1) / 2;
      	while (l < r) 
      		// 获取当前判断的 0 的数量
      		int mid = l + r >> 1;
      		// 如果熵大于目标值,说明 0 的数量太多了,要减小 0 的数量
      		// 如果熵小于目标值,说明 0 的数量太少了,要增加 0 的数量
      		if (h(mid, 23333333 - mid) > 11625907.5798) r = mid; // 减少 0
      		else l = mid + 1; // 增加 0
      	
      	cout << l << endl;
      	return 0;
      
      

      可得:

      11027421
      

      然后我们再验证一下这个结果:

      int main () 
      	printf("%.10lf", h(11027421, 23333333 - 11027421));
      	return 0;
      
      

      得结果:

      11625907.5798144601
      

      正确

      答案

      11027421
      

      完整的代码

      #include <iostream>
      #include <cstring>
      #include <algorithm>
      
      using namespace std;
      
      int gcd(int a, int b) 
      	return b ? gcd(b, a % b) : a;
      
      
      double h(int p0, int p1) 
      	int t0 = p0, t1 = p1;
      	int t = gcd(t0, t1);
      	t0 /= t, t1 /= t;
      	double t2 = t0 + t1;
      	double res = 0;
      	
      	res -= p0 * (t0 / t2) * (log2(t0) - log2(t2));
      	res -= p1 * (t1 / t2) * (log2(t1) - log2(t2));
      	return res;
      
      
      int main () 
      	int l = 1, r = (23333333 + 1) / 2;
      	while (l < r) 
      		int mid = l + r >> 1;
      		if (h(mid, 23333333 - mid) > 11625907.5798) r = mid;
      		else l = mid + 1;
      	
      	cout << l << endl第十四届蓝桥杯大赛软件赛省赛JavaB组解析

      第十四届蓝桥杯省赛c/c++大学B组题解

      第十四届蓝桥杯大赛软件赛省赛-试题 B---01 串的熵 解题思路+完整代码

      第十一届蓝桥杯大赛软件类省赛第二场C/C++大学B组(python解答)

      2023年第十四届蓝桥杯将至来看看第十二届蓝桥杯javaB组题目如何

      第十三届蓝桥杯大赛软件赛省赛(Java 大学A组)

(c)2006-2024 SYSTEM All Rights Reserved IT常识