长沙学院2022蓝桥杯模拟赛一
长沙学院2022蓝桥杯模拟赛一_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJhttps://ac.nowcoder.com/acm/contest/26010#question
目录
A.因子和
B.找数
C.数与连分数
D.文件查找
E.多米诺骨牌
F.财富分配
G.分数鄙视
A.因子和
我提供一个类似于埃氏筛的思路,例如有1,2,3,4四个数,最大是4,我们列举出小于4的每个数的倍数,那么这个倍数就一定含有乘以倍数之前的因数,例如1的四倍是4,那么4就必定含有1这个因数.我们另外开一个数组来记录它们的和即可,含有这个因子就把因子加进对应位置去.
#include<iostream>
#define ll long long
using namespace std;
ll sum[1000006];
void init(int n)
{for(int i=1;i<=n;i++){for(int j=1;j*i<=n;j++){sum[i*j]+=i;}}
}
int main()
{int i,j,t,n;cin>>n;init(n);for(int i=1;i<=n;i++)cout<<sum[i]<<" ";cout<<endl;return 0;
}
B.找数
此题分两种情况讨论,如果两个数数位相同,例如都是三位数,我们可以列出它的方程为f(x)=x*(999-x)这个时候就会发现这是一个开口向下的二次函数,取最大值的时候就是499和500的时候,以此类推可以得出1结论,同位的数,越是接近中间,值也就越大,那么我们只用比较两个数对于中心距离的大小1即可.如果不是同位的数的话就针对大的数进行讨论1,观察函数在它的范围内取最大值即为答案.
#include<iostream>
#include<cmath>
#define int long long
using namespace std;
int change(int x)
{int wei=1,tran=0;int z=x;while(x){tran+=wei*(9-x%10);wei*=10;x/=10;}return tran*z;
}
signed main()
{int l,r,maxx=0,weil=0,weir=0,ll,rr,tt=4;scanf("%lld%lld",&l,&r);ll=l;rr=r;while(ll){ll/=10;weil++;}while(rr){rr/=10;weir++;}if(weir>weil){tt=pow(10,weir)/2-1;if(r<tt){printf("%lld",change(r));}else{printf("%lld",change(tt));}}else if(weir==weil){tt=pow(10,weir)/2-1;if(l<tt&&r<=tt){printf("%lld",change(r));}else if(l<=tt&&r>=tt){printf("%lld",change(tt));}else if(l>tt&&r>tt){printf("%lld",change(l));}}return 0;
}
C.数与连分数
纯模拟题,先把这两个的转换的方法自己算一遍,然后尝试去用代码实现,注意一些特殊情况.
针对于连分数转分数,我们就用两个变量来储存分子和分母,这样来模拟它的加法.
针对于分数转化为连分数就有挺多坑的,一定要在进行模拟的时候进行分子分母的约分,约分了之后注意能否除尽这些情况.另外就是注意输出结果中 ; 和 , 的情况.
#include<iostream>
#include<algorithm>
#include<string>
#define int long long
using namespace std;
string str;
int arr[500];
void change1()
{int k,cnt1,cnt2,cnt3=1,id=0,temp=0;for(int i=1;i<str.size();i++){if(str[i]>='0'&&str[i]<='9'){temp=temp*10+str[i]-'0';}else{arr[id]=temp;temp=0;id++;}}if(id==1){printf("%lld\n",arr[0]);return ;}cnt1=arr[id-1];for(int i=id-2;i>=0;i--){cnt2=arr[i];cnt3=cnt2*cnt1+cnt3;k=cnt3;cnt3=cnt1;cnt1=k;}if(cnt3==1){printf("%lld\n",cnt1);return;}printf("%lld/%lld\n",cnt1,cnt3);
}
void change2()
{int k,temp=0,cnt1,cnt2,cnt3,id=0;for(int i=0;i<str.size();i++){if(str[i]>='0'&&str[i]<='9'){temp=temp*10+str[i]-'0';}else {cnt1=temp;temp=0;}}cnt2=temp;int gc=__gcd(cnt1,cnt2);cnt1/=gc;cnt2/=gc;printf("[");int ma=0;while(cnt1%cnt2!=1){if(cnt1%cnt2==0){printf("%lld]\n",cnt1/cnt2);return;}int gc=__gcd(cnt1,cnt2);cnt1/=gc;cnt2/=gc;printf("%lld",cnt1/cnt2);if(ma==0)printf(";"),ma=1;elseprintf(",");cnt1=cnt1%cnt2;k=cnt1;cnt1=cnt2;cnt2=k;}printf("%lld,%lld",cnt1/cnt2,cnt2);printf("]\n");
}
signed main()
{while(cin>>str){if(str[0]=='[')change1();elsechange2();}return 0;
}
D.文件查找
我用的方法是dfs+双端队列模拟栈(不一定要用双端队列,只需要一个能够实现遍历和模拟栈的储存方式的东西就行,可以尝试数组模拟,推荐去学一下stl容器).题目中存在3种变量,文件夹,文件数,文件名,所以要注意,我们每次输入是判断此时是文件名还是文件,题中说过了,文件名含有一个".",可以依次来区别两者,然后输入文件数进行递归,每次递归进去了就用双端队列去把当前的文件夹名存进去,一直如此,直到遍历到了文件,判断文件和所给的需要查找的文件是不是一样的,是一样的就遍历,把存在双端队列模拟的栈中的文件夹名取出来输出.然后在返回上一层,返回上一层递归时要注意此时已经退出了此文件夹的话,要把文件夹名从双端队列模拟的栈中取出.
对该样例分析
nanqiao.cpp
nanqiao 2
ccsu 1
nanqiao.cpp
nanqiao 1
ccsu.cpp
首先我们输入了nanqiao,因为不含有".",那么就把它存进双端队列模拟的栈内,在进行数字输入,再到ccsu,因为是文件夹,存进栈内,再递归下一层,会发现下一个就是我们要找的nanqiao.cpp.就把模拟栈内的元素全部输出......
#include<iostream>
#include<string>
#include<deque>
using namespace std;
string str,ss;
deque<string>sta;
void dfs(int x)
{string s1;int xx;while(x>0){x--;cin>>s1;int mark=0;for(int i=0;i<s1.size();i++){if(s1[i]=='.'){mark=1;}}if(mark==1){if(s1==str){for(int j=0;j<sta.size();j++){cout<<sta[j]<<"\\";} cout<<s1<<endl;}}else{sta.push_back(s1);cin>>xx;dfs(xx);sta.pop_back();}}return ;
}
int main()
{int t;cin>>str;while(cin>>ss){int mark=0;for(int i=0;i<ss.size();i++){if(ss[i]=='.'){mark=1;}}if(mark==1){if(ss==str)cout<<ss<<endl;}else{sta.push_back(ss);cin>>t;dfs(t);sta.pop_back();}}return 0;
}
E.多米诺骨牌
这题挺多做法的,普遍的就是bfs和模拟,我采用的模拟做法.
因为只有两种会改变其他骨牌形态的骨牌:"\""/".那我们就枚举所有的两种的情况组合来进行处理.就先遍历字符串,当此时遍历的字符不是"|"的时候用l(左端),r(右端)进行记录最开始遍历到的两个的左右端点形态,然后针对它们的形态来进行一段段的处理,例如如果是"/""\"那么中间的牌都会向中间倒下,我这里用了一个区间处理,如果此区间牌数为奇数就会有一张牌保持"|"状态.把这些牌的情况处理完之后,再用l(左端)来记录此时r(右端)的下标和形态,(此时的r(右端)会和后面第一个非"|"的牌产生效果).这样一连串处理完之后,还要注意.如果从左起最先遍历到的非"|"骨牌是"\",那么从一开始到这张牌都要变为"\",同理,最后一张非"|"如果是"/"也会影响这张牌到最后面的情况.
然后就是转义字符,'\\'才能表示出\.
#include<iostream>
#include<cstring>
using namespace std;
struct node
{char ty;int idx;
}l,r;
char str[10000007];
int main()
{scanf("%s",str);int len=strlen(str);int cnt=0;for(int i=0;i<len;i++){if(str[i]!='|'&&cnt==0){l.ty=str[i];l.idx=i;cnt=1;}else if(str[i]!='|'&&cnt==1){r.ty=str[i];r.idx=i;cnt=2;}if(cnt==2){if(l.ty=='/'&&r.ty=='/'){for(int j=l.idx;j<=r.idx;j++)str[j]='/';l=r;cnt=1;}else if(l.ty=='/'&&r.ty=='\\'){int ll=r.idx-l.idx-1;ll/=2;for(int j=l.idx;j<=l.idx+ll;j++)str[j]='/';for(int j=r.idx;j>=r.idx-ll;j--)str[j]='\\'; l=r;cnt=1;}else if(l.ty=='\\'&&r.ty=='\\'){for(int j=l.idx;j<=r.idx;j++)str[j]='\\';l=r;cnt=1;}else if(l.ty=='\\'&&r.ty=='/'){l=r;cnt=1;}}}for(int i=0;i<len;i++){if(str[i]=='/')break;else if(str[i]=='\\'){for(int j=0;j<=i;j++){str[j]='\\';}break;}}for(int i=len-1;i>=0;i--){if(str[i]=='\\')break;else if(str[i]=='/'){for(int j=i;j<len;j++){str[j]='/';}break;}}for(int i=0;i<len;i++)printf("%c",str[i]);return 0;
}
F.财富分配
涉及到了运算符号重载和优先队列.
先定义一个结构体
struct point
{int a,b,x;int power,ans;
}
我们用
bool operator <(const point that)const{return this->power<=that.power;}
来重载运算符"<".(基本格式是这样),这样就可以让结构体的<运算具有意义,然后在定义一个优先队列来储存结构体,结构体就会按照这个小于号来进行排序.
基本思路就是把m块钱一元一元的分给每个人,但是每次都按贪心的思想,分给亏损增长最少的人,那么就是用这个人分了一块钱的情况减去上没有分到这一块钱的情况的大小来维护优先队列:
f(x+1)-f(x),这就是分了一块钱之后这个人的亏损增长值.
power=-a*(int)pow(x+1-b,2)+a*(int)pow(x-b,2);
每次优先队列首一定是增长最少的,那么我们就它从优先队列里面取出来,把钱数+1,在放回优先队列中,保证每一块钱分给一个人之后,亏损增长都是最小的
#include<iostream>
#include<cmath>
#include<queue>
#define int long long
using namespace std;
struct point
{int a,b,x;int power,ans;bool operator <(const point that)const{return this->power<=that.power;}void get_power(){power=-a*(int)pow(x+1-b,2)+a*(int)pow(x-b,2);}void get_ans(){ans=-a*(int)pow(x-b,2);}
}arr[100005];
signed main()
{int n,m,Ans=0;scanf("%lld%lld",&n,&m);for(int i=1;i<=n;i++)scanf("%lld",&arr[i].a);priority_queue<point>qu;for(int i=1;i<=n;i++){scanf("%lld",&arr[i].b);arr[i].x=0;arr[i].get_power();qu.push(arr[i]);}point temp;while(m--){temp=qu.top();qu.pop();temp.x++;temp.get_power();qu.push(temp);}while(qu.size()){temp=qu.top();qu.pop();temp.get_ans();Ans+=temp.ans;}printf("%lld",Ans);return 0;
}
G.分数鄙视
稍微有改变的逆序对板子题.对于样例:
4
1 3 3 5
按照正常情况,zzf学长所得的分数应该是:
1 2 3 4
我们尝试用现在得分来减去他的应有得分得到:
0 1 0 1
你会发现第二次和第四次超出了他的预期,那么它们就不会互相鄙视,因为它们是同一水平的,但是第二次会鄙视第一次,因为第二次的水平比第一次的水平高1等.也就是如果按照第二次的标准,第一次得分应该是2,但是它比而小,这样就产生了一次鄙视.这就是逆序对的板子了,然后我就去套树状数组板子了,可以尝试学逆序对的解法.
#include<iostream>
using namespace std;
int a[100005];
int vis[1000006];
int maxx=0;
int lowbits(int x)
{return x-(x&(x-1));
}
int query(int x)
{int res=0;while(x){res+=vis[x];x-=lowbits(x);}return res;
}
void add(int x)
{while(x<=maxx){vis[x]+=1;x+=lowbits(x);}
}
int main()
{int n,ans=0;scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i]=a[i]-i+100000;maxx=max(a[i],maxx);} for(int i=1;i<=n;i++){ans=(ans+query(a[i]-1))%12345;add(a[i]);}printf("%d",ans);return 0;
}
H.幸福的道路
不会树形dp的我已经可以重开了.
以下为学习树形dp之后补的坑:
思路:
解决该题分两步,先用树形dp去求他的每一天的幸福值,然后在求出每一天幸福值的前提下,按照题目条件用单调队列去求能保证幸福值波动在M的区间长度.
首先是树形dp求每一天幸福值.如果我们求一个点到其他点的最大值,可以用dfs去遍历并且维护这个点的最大的幸福值和次大幸福值.更新父节点的这两个值时,需要用子节点去对他进行更新,(为叶子节点此时次大最大都为0).将子节点中最大值加上两个点的距离,去更新父节点已经存在的次大最大值,并且开一个数组记录每个父节点最大值所在的子节点是哪一个.第二遍dfs则是用父节点去更新子节点.当子节点在父节点的最大值的路径上时,用次大值和两者距离去更新最终贡献,而不在最大值路径时,用父节点最大值和距离去更新,判断是否在最大值路径上前面已经记录过了.
我们用树形dp已经解决了每一天的幸福值后.采用双指针去求区间,并且用两个答案掉队列去维护它.两个单调队列分别维护该区间的最大值和最小值,随着合右指针右移,当两个单调队列的队首相差大于M之后则将序号在前面的点出队,每次取区间最长长度即可.
#include<iostream>
#include<cstring>
using namespace std;
int n,m;
struct node
{int to,val,ne;
}edge[2000006];
int h[1000006],tot=0,sum[1000006];
int d1[1000006],d2[1000006],name[1000006];
int qmax[1000006],qmin[1000006];
void add(int x,int y,int val)
{edge[++tot].to=y;edge[tot].val=val;edge[tot].ne=h[x];h[x]=tot;
}
void dfs_down(int x,int fa)
{ d1[x]=0,d2[x]=0;for(int i=h[x];i!=-1;i=edge[i].ne){int y=edge[i].to;if(y==fa)continue;dfs_down(y,x);int d=d1[y]+edge[i].val;if(d>=d1[x]){d2[x]=d1[x];d1[x]=d;name[x]=y;}else if(d>=d2[x])d2[x]=d;}return ;
}
void dfs_up(int x,int fa)
{for(int i=h[x];i!=-1;i=edge[i].ne){int y=edge[i].to;if(y==fa)continue;if(y==name[x])sum[y]=max(d2[x],sum[x])+edge[i].val;elsesum[y]=max(d1[x],sum[x])+edge[i].val;dfs_up(y,x);}return ;
}
int main()
{int x,y;memset(h,-1,sizeof h);scanf("%d%d",&n,&m);for(int i=2;i<=n;i++){scanf("%d%d",&x,&y);add(i,x,y);add(x,i,y);}dfs_down(1,0);dfs_up(1,0);for(int i=1;i<=n;i++)sum[i]=max(sum[i],d1[i]);int len=0,l=1,hmax=0,tmax=-1,tmin=-1,hmin=0;for(int r=1;r<=n;r++){while(tmax>=hmax&&sum[qmax[tmax]]<=sum[r])tmax--;qmax[++tmax]=r;while(tmin>=hmin&&sum[qmin[tmin]]>=sum[r])tmin--; qmin[++tmin]=r;while(sum[qmax[hmax]]-sum[qmin[hmin]]>m){l=min(qmax[hmax],qmin[hmin]);l++;if(tmax>=hmax&&l>qmax[hmax])hmax++;if(tmin>=hmin&&l>qmin[hmin])hmin++;}len=max(len,r-l+1);}printf("%d",len);return 0;
}
总结:本场比赛以模拟为主,涉及少量算法和stl容器.dp也没有出简单题,贪心也出的比较难.
长沙学院2022蓝桥杯模拟赛一相关推荐
- 2022 第十四届蓝桥杯模拟赛第一期(题解与标程)
第十四届蓝桥杯模拟赛第一期 1. 二进制位数 问题描述 答案提交 参考答案 2. 晨跑 问题描述 答案提交 参考答案 3. 调和级数 问题描述 答案提交 参考答案 程序验证 4. 山谷 问题描述 答案 ...
- 【蓝桥杯Web】大一小白参与蓝桥杯模拟赛二期web组体会
目录 前言 一.相关比赛介绍 1.ACM国际大学生程序设计竞赛 2.蓝桥杯 3.GPLT团队程序设计天梯赛 4.leetcode周赛和双周赛 5.PAT 二.蓝桥杯 1.应该参加蓝桥杯吗? 2.如何进 ...
- 第十三届蓝桥杯模拟赛第二期JAVA组个人题解
第十三届蓝桥杯模拟赛第二期JAVA组个人题解 文章目录 第十三届蓝桥杯模拟赛第二期JAVA组个人题解 题目1 题目2 题目3 题目4 题目5 题目6 题目7 题目8 题目9 题目10 题目1 小蓝的I ...
- 第十三届蓝桥杯模拟赛(第三期)试题与题解 C++
文章目录 第十三届蓝桥杯模拟赛(第三期)试题与题解 1.试题A 题解:数制转换 2.试题B 题解:枚举 3.试题C 题解:枚举 4.试题D 题解:最小生成树 5.试题E 方法一:暴力求和 方法二:一维 ...
- 第十三届蓝桥杯模拟赛(第二期)试题与题解 C++
第十三届蓝桥杯模拟赛(第二期)试题与题解 1.试题A [问题描述] 小蓝的IP地址为 192.168. * .21,其中 * 是一个数字,请问这个数字最大可能是多少 ? 题解 IP地址由四个字节组 ...
- 2020年蓝桥杯模拟赛2020.3.25直播笔记
2020年蓝桥杯模拟赛解题报告(CPP版本) 第八题 长草的bfs写法[我想暴力模拟O kmn] 深搜会爆 bfs像投到水里的涟漪 问题: const int dx[] = {1, 0, -1, 0} ...
- 蓝桥杯模拟赛第二场(web)
文章目录 蓝桥杯模拟赛第二场(web) 1 卡片化标签页 2 随机数生成器 3 个人博客 4 学生成绩统计 5 水果摆盘 6 给页面化个妆 7 小兔子爬楼梯 8 时间管理大师 9 购物车 10 菜单树 ...
- 第十四届蓝桥杯模拟赛(第三期)Java组个人题解
第十四届蓝桥杯模拟赛(第三期)Java组个人题解
- 2022蓝桥杯省赛C++A组初尝试
前言 耗时三个半小时,看看自己不懂的有多少,以便明确后续备赛2023方向 耗时3个半小时,只拿了18分,没学过,时间再多也做不出来,有奥数那感觉了 据说蓝桥杯省3得做对 2填空 + 2大题(30分), ...
最新文章
- opencv打开raw格式图像
- 牛客题霸 SQL5 查找所有员工的last_name和first_name以及对应部门编号dept_no
- boost::fusion::traits::is_sequence用法的测试
- xaml语言建立首个win8 Metro应用,rss阅读器
- Apollo自动驾驶入门课程第⑨讲 — 控制(上)
- 云原生人物志 | Pulsar翟佳:社区的信任最重要
- Gurobi建模遇到的坑
- 链式延迟执行DOME
- php smarty 后台,smarty后台文件常用方法及说明
- 手把手从零开始学习树莓派教程
- Tecplot360 作图经验
- 数字电视复用器中的PCR矫正技术
- 深度学习在语音识别中的算法、应用、数据集、行业分析
- 中国智慧建造投资前景预测与十四五战略规划建议报告2022年版
- 苹果发布的Mac Pro就是“渣渣”?网友疯狂吐槽
- bugku misc QAQ
- 全国一半人跑长沙,长沙一半人跑哪?
- 03-GeoServer WMS服务参数讲解
- Bug的严重程度(缺陷程度)有哪几种。。。。
- 气体灭火系统的应用与选型 (装载)