计蒜客2020蓝桥杯大学A组模拟赛题解

蓝桥杯的话,去年拿了C++组的国二。今年报名了新成立的Python组,不知道能不能摸到国一的鱼

模拟赛链接如下:

https://www.jisuanke.com/contest/6510?view=challenges

打蓝桥的策略依旧很简单:前面60~70min 搞填空,后面刷大题,注意先看完所有题,不要只按顺序


A. 计算周长

一个很显然的想法是a和b和c尽量接近。当然还是枚举出来更为靠谱。我们给V分解因子。穷举所有可能a,b,c取min即可

#include <cstdio>
#include <vector>
#include <algorithm>
#define int long longusing namespace std;vector<int> f,g;
int S=2E9;signed main(){int V=932065482;for(int i=2;i*i<=V;i++)if(V%i==0)while(V%i==0) {f.push_back(i);V /= i;}if(V>1)f.push_back(V);do{g.clear();g.push_back(f[0]);for(int i=1;i<f.size();i++)g.push_back(g.back()*f[i]);for(int i=0;i<f.size();i++)for(int j=i;j<f.size();j++){int a=g[i],b=g[j]/g[i],c=g.back()/g[j];S=min(S,2*(a*b+a*c+b*c));if(S==46925458)printf("%lld %lld %lld\n",a,b,c);}}while(next_permutation(f.begin(),f.end()));printf("%lld",S);return 0;
}

B. 七巧板

第二题让我有些犯难,这个直接用程序搞似乎不是很容易。能不能手算呢?

从平面分割数想起,

加一条直线,最多可以增加6个区域

那么第二条似乎最多可以增加到7个区域了,那么答案是不是7+6+7+8+9+10呢?

想要验证但是时间不多,先填上就好。事实上,47就是正确的

C. 苹果

又是一道比较难搞的题。

很快就放弃了手算。事实上,如果你足够老司机,那么就会想起2017 ICPC广西邀请赛中,对子和顺子那题。唯一的区别在于,对子的组成从2个一组,成了3个一组。

那题可以贪心。这题中,优先组“对子”的优势似乎并不太明显,因此我没有决定贪心(貌似某些贪心也能得到62,但正确性依旧不是很明显,先留坑)。

好在用dp求解的方法基本不变。我们用 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示到第i个篮子,预留 ( i − 1 , i , i + 1 ) (i-1,i,i+1) (i−1,i,i+1)的个数为j,预留 ( i , i + 1 , i + 2 ) (i,i+1,i+2) (i,i+1,i+2)的个数为k,那么转移方程如下

d p [ i + 1 ] [ k ] [ l ] = m a x ( d p [ i + 1 ] [ k ] [ l ] , d p [ i ] [ j ] [ k ] + ( a [ i + 1 ] − j − k − l ) / 3 + j ) ; dp[i + 1][k][l] = max(dp[i + 1][k][l], dp[i][j][k] + (a[i + 1] - j - k - l) / 3 + j); dp[i+1][k][l]=max(dp[i+1][k][l],dp[i][j][k]+(a[i+1]−j−k−l)/3+j);

我们看到对于第i+1步,去掉 j + k + l j+k+l j+k+l剩下的我们尽量组对,然后加上已经能成顺子的 j j j即是一种可行方案。

另外对于 j , k j,k j,k上限,实际上显然能看出来不超过2。

#include <cstdio>
#include <algorithm>using namespace std;int dp[38][3][3], a[38] = {0, 7, 2, 12, 5, 9, 9, 8, 10, 7, 10, 5, 4, 5, 8, 4, 4, 10, 11, 3, 8, 7, 8, 3, 2, 1, 6, 3,9, 7, 1}, ans;int main() {for (int i = 0; i <= 30; i++)for (int j = 0; j < 3; j++)for (int k = 0; k < 3; k++)dp[i][j][k] = -1E9;dp[0][0][0] = 0;for (int i = 0; i < 30; i++)for (int j = 0; j < 3; j++)for (int k = 0; k < 3; k++)for (int l = 0; l < 3; l++)if (j + k + l <= a[i + 1])dp[i + 1][k][l] = max(dp[i + 1][k][l], dp[i][j][k] + (a[i + 1] - j - k - l) / 3 + j);for (int j = 0; j < 3; j++)for (int k = 0; k < 3; k++)ans = max(ans, dp[30][j][k]);printf("%d", ans);return 0;
}

当然,对于大部分人来说,短时间在没有经验的情况下,想好一个不错的状态并且dp有点困难,那么不妨尝试一下暴力搜索加剪枝,代码如下,大概跑完需要将近十分钟(慢慢扩大数据范围来估计时间,要有耐心咯)。

#include <cstdio>
#include <algorithm>using namespace std;int a[38] = {0, 7, 2, 12, 5, 9, 9, 8, 10, 7, 10, 5, 4, 5, 8, 4, 4, 10, 11, 3, 8, 7, 8, 3, 2, 1, 6, 3, 9, 7,1};int ans;void dfs(int x, int res) {if (x > 30) {ans = max(ans, res);return;}if(x>5&&a[x-5]&&a[x-4]&&a[x-3])  //假如留下了连续三个,那么为啥不组顺子呢return ;if(x>4&&a[x-4]>2)  //假如某个位置比3大当然也不可以return ;for (int j = a[x]/3; a[x] - j * 3 <= 4; j--) {  //不组顺a[x] -= j * 3;dfs(x + 1, res + j);a[x] += j * 3;}if (x > 2)  //组顺for (int i = 1; i <= a[x] && i < 3; i++)if (a[x - 2] >= i && a[x - 1] >= i && a[x] >= i) {a[x - 2] -= i;a[x - 1] -= i;a[x]-=i;for (int j = a[x]/3; a[x] - j * 3 <= 4; j--) {a[x] -= j * 3;dfs(x + 1, res + j+i);a[x] += j * 3;}a[x - 2] += i;a[x - 1] += i;a[x] += i;}
}int main() {dfs(1, 0);printf("%d", ans);return 0;
}

D. 天气与活动

学过自然语言处理的同学们都知道这个叫隐马尔可夫链,因为数据不大,我们仅仅采用贝叶斯公式就足够了

P ( [ 晴 天 , 雨 天 , 雨 天 ] ∣ [ 散 步 , 购 物 , 打 扫 卫 生 ] ) = P ( Q ∣ O ) = P ( Q ) ∗ P ( O ∣ Q ) ∑ q P ( O ∣ q ) P ( q ) P([晴天,雨天,雨天]|[散步,购物,打扫卫生])=P(Q|O)=\frac{P(Q)*P(O|Q)}{\sum_q P(O|q)P(q)} P([晴天,雨天,雨天]∣[散步,购物,打扫卫生])=P(Q∣O)=∑q​P(O∣q)P(q)P(Q)∗P(O∣Q)​

分 子 = ( 0.6 ∗ 0.4 ∗ 0.7 ) ∗ ( 0.6 ∗ 0.4 ∗ 0.5 ) = 0.168 ∗ 0.12 = 0.02016 分子=(0.6*0.4*0.7)*(0.6*0.4*0.5)=0.168*0.12=0.02016 分子=(0.6∗0.4∗0.7)∗(0.6∗0.4∗0.5)=0.168∗0.12=0.02016

分母有八种情况,我们此处用程序枚举即可,大约为 0.043928 0.043928 0.043928

#include <cstdio>using namespace std;double o[2][3] = {{0.6, 0.3, 0.1},{0.1, 0.4, 0.5}};
double q[2][2] = {{0.6, 0.4},{0.3, 0.7}};
double ans;int main() {for (int i = 0; i < 2; i++)for (int j = 0; j < 2; j++)for (int k = 0; k < 2; k++) {ans += o[i][0] * o[i][1] * o[i][2]*q[0][i]*q[i][j]*q[j][k];}printf("%lf",ans);return 0;
}

因此答案为 0.45893 0.45893 0.45893

E. 方阵

又是一道有点恼人的题目,当然你可以写一个不那么暴力的暴力,然后等待许久,比较保险。足够自信或者没有耐心的话,可以写正解,方法是二维前缀和。代码如下

#include <cstdio>
#include <algorithm>
#include <vector>using namespace std;long long ans;
int sum[1005][1005];int area(int a, int b, int c, int d){a+=500,b+=500,c+=501,d+=501;return sum[c][d]+sum[a][b]-sum[c][b]-sum[a][d];
}int main() {for (int i = -500; i <= 500; i++)for (int j = -500; j <= 500; j++)if (i * i + j * j <= 500 * 500 && __gcd(i, j) == 1)sum[i+501][j+501]++;for (int i = 1; i <= 1001; i++)for (int j = 1; j <= 1001; j++)sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];for (int i = 1; i <= 1000; i++)for (int j = 1; j <= 1000; j++)ans+=area(max(-500,1-i),max(-500,1-j),min(1000-i,500),min(1000-j,500));printf("%lld",ans%1000000007);return 0;
}

注意为了方便测试小数据,1000,500这些常量还是赋值比较好,以便改动。


由于参加的是python组,以下代码均为python书写,可能会发生超时。

参加蓝桥杯时,大题的实现,务必要多加小心,不可以有低级错误!


F. 被袭击的村庄

基本上是一道模拟裸题,不多叙述。

这一题题意有误,后来听说是前面三个数实际上应该三种建筑的耐久度为0的总数。

n,m=map(int,input().split())
a=[0]+[int(x) for x in input().split()]
k,w=map(int,input().split())
A=[[0]]
for i in range(1,k+1):A.append([0]+[int(x) for x in input().split()])N=[[0]]
M=[[0]*(m+1) for i in range(n+1)]
for i in range(1,n+1):N.append([0]+[int(x) for x in input().split()])for j in range(1,m+1):M[i][j]=a[N[i][j]]q=int(input())cnt=[0]*4
ans=0for i in range(q):o,x,y=map(int,input().split())up = max(x - k // 2, 1); dn = min(x + k // 2, n); le = max(y - k // 2, 1); ri = min(y + k // 2, m)for i in range(up,dn+1):for j in range(le,ri+1):M[i][j] = max(M[i][j] - A[i - (x - k // 2) + 1][j - (y - k // 2) + 1], 0)if not o:for i in range(up,dn+1):for j in range(le,ri+1):for fx in range(-1,2):for fy in range(-1,2):if fx or fy:u=i+fx;v=j+fyif u > 0 and u <= n and v > 0 and v <= m:M[u][v] = max(M[u][v] - w, 0)
for i in range(1,n+1):for j in range(1,m+1):if not M[i][j]:cnt[N[i][j]]+=1ans+=a[N[i][j]]-M[i][j]
print(cnt[1],cnt[2],cnt[3])
print(ans)

G. 建立联系

实际上就是一道克鲁斯卡尔算法求生成树的问题,不同的是只需要做到剩下k个强连通分量即可退出。

有人可能会怀疑这样贪心为什么可以呢?

这里暂时留坑。不过既然克鲁斯卡尔算法成立,那么猜测类似的算法也是很有道理的。

n,m,k=map(int,input().split())
E=[]
for i in range(m):a,b,c=map(int,input().split())E.append((c,a,b))E.sort()
cnt=n
fa=[i for i in range(0,n+1)]def fis(x):if fa[x]==x:return xfa[x]=fis(fa[x])return fa[x]ans=0for i in range(m):if fis(E[i][1])!=fis(E[i][2]):ans+=E[i][0]fa[fis(E[i][1])]=fis(E[i][2])cnt-=1if cnt<=k:print(ans)exit(0)
print(ans)

H. 最短路

应该算经典题目了吧。从起点对正图和反图各自求一次单源最短路,然后所有值相加即可。反图的单源最短路必然和正图的每个点到源的最短路对应

from queue import PriorityQueueclass Dij:def solve(self,E,n,s):self.ans=[int(1E18)]*(n+1)self.ans[s]=0Q=PriorityQueue()Q.put((0,s))while not Q.empty():w,u=Q.get()if self.ans[u]<w:continuefor i in E[u]:if self.ans[i[0]]>self.ans[u]+i[1]:self.ans[i[0]]=self.ans[u]+i[1]Q.put((self.ans[i[0]],i[0]))A=Dij()
B=Dij()T=int(input())
for i in range(T):n,m=map(int,input().split())E=[[] for i in range(n+1)]F=[[] for i in range(n+1)]for i in range(m):u,v,w=map(int,input().split())E[u].append((v,w))F[v].append((u,w))A.solve(E,n,1)B.solve(F,n,1)ans=0for i in range(2,n+1):ans+=A.ans[i]+B.ans[i]print(ans)

I. 迷宫

这一题是一个典型的广搜。注意理解题意,题目中如果一个点有传送门,将会立即进行传送,而不能转而进行上下左右移动(当时理解错了,真坑)。于是,每一次四个方向扩展新状态,如果有传送门,我们需要把传送门尽头的那个点扔进队列,否则把自身扔进队列。在传送门中跳跃时不断判断是否已经到达终点。

实现中细节还是很多的,要理清思路再写。

class queue:def __init__(self,n):self.q=[0]*nself.hd=0self.tl=0def put(self,x):self.q[self.tl]=xself.tl+=1def get(self):self.hd+=1return self.q[self.hd-1]def empty(self):return self.hd==self.tln,m=map(int,input().split())
s=[[0]]
for i in range(1,n+1):s.append("0"+input())
q=int(input())
U=dict()
for i in range(q):a,b,c,d=map(int,input().split())U[(a,b)]=(c,d)
p=list(map(int,input().split()))
Q=queue(1000000-m)
vis=[[False]*1001 for i in range(1001)]def extend(x,y,stp):f=Falsewhile s[x][y]!='*' and not vis[x][y] and U.__contains__((x,y)):if [x,y]==p:print(stp)exit(0)vis[x][y]=Truex,y=U[(x,y)]f=Trueif [x,y]==p:print(stp)exit(0)if s[x][y]!='*' and not vis[x][y]:Q.put((x,y,stp))vis[x][y]=Truereturn fextend(1,1,0)
while not Q.empty():x,y,stp=Q.get()for j in [(0,1),(1,0),(0,-1),(-1,0)]:u=x+j[0];v=y+j[1]if u>0 and u<=n and v>0 and v<=m and s[u][v]!='*' and not vis[u][v]:extend(u,v,stp+1)
print('No solution')

J. 涂墙

这一题是一道难题,基本上也符合蓝桥杯最后一题的定位。赛场上最后一题,不要浪费时间想着正解,赶紧把分水水到就行了。

回忆一下一维的情况。有箱子中1到n编号的小球,我们每次有放回地取,期望多少次能取到所有小球呢?

当我们首次取到x个小球时,下一个小球在x之外的概率为 ( n − x ) / n (n-x)/n (n−x)/n,因此,能取到新球的期望次数为 n / ( n − x ) n/(n-x) n/(n−x),因此,总期望等于 ∑ i = 0 n − 1 n / ( n − i ) \sum_{i=0}^{n-1} n/(n-i) ∑i=0n−1​n/(n−i)

(附:如果这里每个小球取出的概率不同,则需要用到min/max容斥来解)

那么对于二维的情况呢?

我们假设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示首次填下i行j列经过的期望步数,不难发现,可以由左下的三种状态转移而来,但三种情况的概率,似乎并不容易求解。经过一番猜测也没有成功。

参考另一位博主的解法:https://blog.csdn.net/JiangHxin/article/details/104059688

发现原来如此巧妙。将正向的状态改成定义为逆向的状态,把dp定义为已经填满i行和j列的前提下,转移方程便成了另一幅模样,

d p [ i ] [ j ] = i / n ∗ j / n ∗ d p [ i ] [ j ] + i / n ∗ ( n − j ) / n ∗ d p [ i ] [ j + 1 ] + ( n − i ) / n ∗ j / n ∗ d p [ i + 1 ] [ j ] + ( n − i ) / n ∗ ( n − j ) / n ∗ d p [ i + 1 ] [ j + 1 ] ; dp[i][j] = i/n * j/n * dp[i][j] + i/n * (n-j)/n * dp[i][j+1] + (n-i)/n * j/n * dp[i+1][j] + (n-i)/n * (n-j)/n * dp[i+1][j+1] ; dp[i][j]=i/n∗j/n∗dp[i][j]+i/n∗(n−j)/n∗dp[i][j+1]+(n−i)/n∗j/n∗dp[i+1][j]+(n−i)/n∗(n−j)/n∗dp[i+1][j+1];

其中左右都包含 d p [ i ] [ j ] dp[i][j] dp[i][j]这一项,没有关系,移项求解即可。

这里状态定义和巧妙的方程求解是需要品味的。

def solve():n,m=map(int,input().split())X=[0]*(n+1)Y=[0]*(n+1)a=0;b=0for i in range(m):x,y=map(int,input().split())if not X[x]:X[x]=1a+=1if not Y[y]:Y[y]=1b+=1dp=[[0]*(n+2) for i in range(n+2)]for i in range(n,a-1,-1):for j in range(n,b-1,-1):x=n*n-i*jif x:dp[i][j]=i*(n-j)/x*dp[i][j+1]+(n-i)*j/x*dp[i+1][j]+(n-i)*(n-j)/x*dp[i+1][j+1]+1.0*n*n/xprint(dp[a][b])    T=int(input())
for i in range(T):solve()

计蒜客2020蓝桥杯大学A组模拟赛题解相关推荐

  1. 计蒜客 2020 蓝桥杯大学 A 组省赛模拟赛 (一)题目及解析

    新手,欢迎交流,剩下D题不知如何下手,望大佬指教. 计蒜客 2020 蓝桥杯大学 B 组省赛模拟赛 (一)题目及解析 文章目录 A. 结果填空:计算周长 B. 结果填空:七巧板 C. 结果填空:苹果 ...

  2. 计蒜客 2020 蓝桥杯大学 B 组省赛模拟赛 (一)题目及解析

    新手,欢迎交流,更新完毕. 计蒜客 2020 蓝桥杯大学 A 组省赛模拟赛 (一)题目及解析 文章目录 A. 结果填空:有趣的数字 B. 结果填空:爬楼梯 C. 结果填空:七巧板 D. 结果填空:苹果 ...

  3. 计蒜客 2020 蓝桥杯大学 B 组省赛模拟赛(一)

    题目传送门 建立了自己的个人博客,朝着秃头的路上一去不返... 作者是个打铁弱鸡,若各位大佬发现了错误请在评论指出. A. 结果填空:有趣的数字 蓝桥杯标准的送温暖题,枚举每个数判断是否含有数字5并进 ...

  4. 【计蒜客模拟赛系列】-计蒜客2021年8月普及组模拟赛

    提前:本文中部分代码和思路有借鉴或摘抄计蒜客官方题解 赛后总结 本次模拟赛的难度总算正常了些 个人战绩: 220/400,排名61 ,太弱了,一大堆AK爷 题目质量评价: 题目相比CSP-J还是简单了 ...

  5. 计蒜客 2020 蓝桥杯省赛 B 组模拟赛(五)E区间dp H 裴蜀 J dp A-J 权值线段树

    题目链接 因为要去笔试.所以只打了两个小时,有点求快,很多细节没写好就匆匆交,而且没有检查,打的有点菜 C-煎牛排 做法: 所有的面的个数sum=2*n   然后sum/(2*k)即可. ans=ma ...

  6. 计蒜客 2020 蓝桥杯省赛 B 组模拟赛(五)

    结果填空:卡片游戏 1000ms 131072K 蒜头君设计了一个双人游戏,在桌面上放置一排 nn 张卡片,第 ii 张卡片上有一个数字 a_iai​.两个人轮流取走一张卡片,直至全部取完.注意每次只 ...

  7. 2020 蓝桥杯大学 B 组省赛模拟赛(一) C. 结果填空:七巧板

    文章目录 1.题目: 2.解法: 3.此题分析: 4.代码实例: 1.题目: 求问在以下图案的大三角形内部添加五条直线最多可以将大三角形分成多少个区域. 例如下图一共有 7 个区域. 请在下图的基础上 ...

  8. 2020 蓝桥杯大学 B 组省赛模拟赛 七巧板

    题目链接 题目链接 题意 在下图的基础上添加五条直线,最多可以将大三角形分成多少个区域 思路 平面划分,每画一条直线,比上次画的直线穿过的直线多一,即每画一条直线比上次画一条直线造成的块数多一 答案为 ...

  9. 2021年 第十二届蓝桥杯第二期校内模拟赛题解(Java版)

    时隔多日,终于会写一些简单DP了哈哈哈! 稍微改版,方便阅读,若有错,请指出 2019年 第十届蓝桥杯省赛题解(JavaB组版) 2020年 第十一届蓝桥杯第一场省赛题解(JavaB组版) 2020年 ...

最新文章

  1. 智能交通:影响人类未来10-40年的重大变革
  2. 【客户下单】后台提供webservice服务接收数据
  3. DDD理论学习系列(11)-- 工厂
  4. 大数据之Spark简介及RDD说明
  5. python位运算符_NumPy按位运算符解析和实例详解
  6. 1218数据库操作工具类的使用
  7. 将python中的小数直接进位的函数_python保留小数位的三种实现方法
  8. 怎么去掉网页上复制到word的文章中各种符号例如向下箭头(↓)?
  9. Python的第三方库pillow
  10. 合肥信息技术职业学院计算机模拟考试准考证,【通知】全国计算机等级考试模拟测试通知...
  11. c++ 循环控制语句 while语句 do...while语句 for语句 for循环
  12. vue 实现数字滚动卡片
  13. @ComponentScan注解
  14. 关于iPhone尺寸与分辨率
  15. 用Java模拟斗地主游戏
  16. yocto项目下载与编译
  17. 【Java】Java中GUI之布局管理器
  18. 常用的HTTP请求方法
  19. 数据分析案例-足球运动员分析
  20. 另一棵树的子树(你一定要会的基础面试题)

热门文章

  1. 玩游戏玩久了手机发烫卡顿怎么办?LDR6020方案助力手机散热器 实现快速降温
  2. 网络系统安全——MS15_034漏洞利用与安全加固
  3. windows修改远程端口
  4. Android系统之路(初识MTK) ------ OTA打包ROM安装系统img等到ZIP
  5. nextflow nf-core download ena/ncbi fastq data
  6. MybatisPlus动态修改表名
  7. 机械臂速成小指南(十八):圆弧规划
  8. 【干货人生篇】过早优化的陷阱!
  9. 魅族手机安装应用apk失败
  10. mybatis联表查询且统计数据