鄙人大一,第一次有幸参加蓝桥杯b组c。以下是本人的做题全过程,注意了!!!!不一定是正确答案!! 如果有误,还请大佬们指点指点。
【问题描述】
小蓝准备用 256MB 的内存空间开一个数组,数组的每个元素都是 32 位
二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问
256MB 的空间可以存储多少个 32 位二进制整数?
思路
当时想错了,想都没想直接就除了32…答案应该是 67108864(256 * 1024 * 1024 / 4) 。
【问题描述】
小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。
小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,
就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从 1 拼到多少。
例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10,
但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。
现在小蓝手里有 0 到 9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1
拼到多少?
思路
做的时候,信誓旦旦打出代码,提交答案 3832 赛后看到别人 3831 ???王德发??好吧是我没减1…草率了。
#include
using namespace std;
int a[10];
bool judge(int i)
{
while(i){
if(a[i%10]>=1){
a[i%10]--;
}
else return 0;
i/=10;
}
return 1;
}
int main()
{
for(int i=0;i<=9;i++){
a[i]=2021;
}
for(int i=1;i<=100000;i++){
if(judge(i)){
;
}
else {
cout<<i-1;
break;
}
}
return 0;
}
【问题描述】
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,
那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 个整点 {(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},即横坐标
是 0 到 1 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数
的点。这些点一共确定了 11 条不同的直线。
给定平面上 20 × 21 个整点 {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},即横
坐标是 0 到 19 (包含 0 和 19) 之间的整数、纵坐标是 0 到 20 (包含 0 和 20) 之
间的整数的点。请问这些点一共确定了多少条不同的直线。
思路
这题做的时候呢,一开始是想手写看看能不能写出来,推了有那么一段时间,用排列组合,然后排除同x同y的,最后发现…不对劲啊,斜着也可以重合。。。然后突然想到19年还是20年有一题是线分成多少个面的…要暴力存之前的线,然后发现套在这个题上也可以,所以就有了以下的思路。
直接开个结构体数组存每条线的k,b值最后看结构体数组的大小就是答案了,。但是写的时候有个问题,垂直于x,y的时候怎么处理?然后我就想,直接不处理了,画图发现垂直于x的不就是20条,垂直于y的不就是21条。那好办了,于是就有了下面的代码。答案应该是 40257
#include
using namespace std;
struct node {
double k,b;
}s[1000000];
int p; //线的个数
double k,b;
void f(int x1,int y1,int x2,int y2)
{
k=(double)(y1-y2)/(double)(x1-x2);//不用考虑x1==x2,y1==y2了
b=(double)(y1*(x1-x2)-x1*(y1-y2))/(x1-x2); //手推公式
}
int main()
{
int n=19,m=20;
for(int x1=0;x1<=n;x1++){
for(int y1=0;y1<=m;y1++){
for(int x2=0;x2<=n;x2++){
for(int y2=0;y2<=m;y2++){
if(x1==x2||y1==y2){
//特殊处理,在答案直接加垂直于x,y的线,所以不用算
continue;
}
f(x1,y1,x2,y2); //计算当前两点的k,b值
int flag=1;
for(int i=1;i<=p;i++){
if(k==s[i].k&&b==s[i].b){
flag=0;
break;
}
}
if(flag){
//如果之前没有这个线,就可以存起来
s[++p].k=k;
s[p].b=b;
}
}
}
}
}
cout<<p+20+21;//加上垂直的答案;
return 0;
}
【问题描述】
小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝
规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、
宽、高。
小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上
分别堆 L、W、H 的货物,满足 n = L × W × H。
给定 n,请问有多少种堆放货物的方案满足要求。
例如,当 n = 4 时,有以下 6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、
2 × 2 × 1、4 × 1 × 1。
请问,当 n = 2021041820210418 (注意有 16 位数字)时,总共有多少种
方案?
思路
一开始想着能不能暴力以下??估计大家都有这样的想法吧,当然了,肯定跑不出来的,这么大的数。然后我就往下看了,最后才回来做的,我发现好像有个规律,找三个数相乘等于一个数,其实这三个数都是这个数的因子。所以思路就出来了,找出n的所有因子,三层循环暴力一下组合方法就行了。答案应该是 2430
#include
#define ll long long
using namespace std;
set <ll > s; //用set能避免去重的麻烦操作
ll a[100000],p; //把set的数存到数组,又能化简遍历难度。
int main()
{
ll n=2021041820210418;
for(ll i=1;i<=sqrt(n);i++){
//开方优化
if(n%i==0){
s.insert(i); //无脑放就行,反正能去重
s.insert(n/i);
}
}
set <ll > :: iterator it;
for(it=s.begin();it!=s.end();it++){
a[++p]=*it;
}
int co=0;
for(int i=1;i<=p;i++){
for(int j=1;j<=p;j++){
for(int k=1;k<=p;k++){
if(a[i]*a[j]*a[k]==n){
co++;
}
}
}
}
cout<<co;
return 0;
}
【问题描述】
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图
中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点
之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条
长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无
向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
思路
这个应该蛮容易想到的,就是图论嘛,根据题意存边,存完之后跑一次弗洛伊德就行了,虽然复杂度高,但是代码简洁,用dij什么也行。代码稍微复杂一点。答案应该是 10266837
#include
#define ll long long
using namespace std;
int G[2050][2050];
int INF=200000000;
int gcd(int a,int b)
{
if(b==0)return a;
return gcd(b,a%b);
}
int main()
{
for(int i=1;i<=2021;i++){
for(int j=1;j<=2021;j++){
G[i][j]=INF;
}
}
for(int i=1;i<=2021;i++){
//按题意建图
for(int j=1;j<=2021;j++){
if(abs(i-j)<=21){
int lcm=i*j/gcd(i,j); //最小公倍数
G[i][j]=min(G[i][j],lcm); //注意不要直接存,会有重边
}
}
}
for(int k=1;k<=2021;k++){
//弗洛伊德模板
for(int i=1;i<=2021;i++){
if(G[i][k]==INF)continue; //小小优化
for(int j=1;j<=2021;j++){
if(G[k][j]==INF)continue;
G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
}
}
}
cout<<G[1][2021];
return 0;
}
【问题描述】
小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取
了当前的时间,用一个整数表示,值为从 1970 年 1 月 1 日 00:00:00 到当前时
刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要
显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。
【输入格式】
输入一行包含一个整数,表示时间。
【输出格式】
输出时分秒表示的当前时间,格式形如 HH:MM:SS,其中
HH 表示时,值
为 0 到 23,MM 表示分,值为 0 到 59,SS 表示秒,值为 0 到 59。时、分、秒
不足两位时补前导 0。
【样例输入 1】
46800999
【样例输出 1】
13:00:00
【样例输入 2】
1618708103123
【样例输出 2】
01:08:23
思路
这个题总体看上去不难,但是一开始我不知道毫秒跟秒怎么换算,最后是看第一个样例得出来的结果!!! 1秒等于1000毫秒,这道题比较好人,可以直接去掉毫秒,也就是一开始的n让它除以1000就行,然后得出来的结果是多少秒,然后在用多少秒除以60得出多少分钟,然后多少分钟除以60得出多少时,然后时,分,秒,都各自取模就好。注意一下输出,就行。
#include
#define ll long long
using namespace std;
int main()
{
ll n;
cin>>n;
n/=1000;
ll s,f,m;//s是时,f是分,m是秒
m=n;
f=m/60;
s=f/60;
m%=60;
f%=60;
s%=24;
if(s<=9){
cout<<0<<s;
}
else cout<<s;
cout<<':';
if(f<=9){
cout<<0<<f;
}
else cout<<f;
cout<<':';
if(m<=9){
cout<<0<<m;
}
else cout<<m;
return 0;
}
【问题描述】
你有一架天平和 N 个砝码,这 N 个砝码重量依次是 W1, W2, · · · , W**N。
请你计算一共可以称出多少种不同的重量?
注意砝码可以放在天平两边。
【输入格式】
输入的第一行包含一个整数 N。
第二行包含 N 个整数:W1, W2, W3, · · · , W**N。
【输出格式】
输出一个整数代表答案。
【样例输入】
3
1 4 6
【样例输出】
10
思路
一眼看上去,呦,这不是dp嘛,第二眼看上去,确认过眼神…01背包?嗯,不太像 有点特别,多了个相减,不过道理是不变的 ,但是dp的条件不知道有没有写齐全,感觉有点问题。。。 用dfs应该能过一些点,但是应该会超时。
#include
#define ll long long
using namespace std;
int dp[105][100005]; //数据保证N个砝码总重不超过 100000
int n;
int v[105];
int m; //所有的重量加起来,方便dp的第二层循环
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&v[i]);
m+=v[i];
}
for(int i=0;i<=n;i++){
//预处理0处的值
dp[i][0]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(dp[i-1][j]==1){
//不要v[i]的情况
dp[i][j]=1;
}
else if(j>=v[i]&&dp[i-1][j-v[i]]==1){
//加一个v[i]的情况
dp[i][j]=1;
}
else if(j+v[i]<=m&&dp[i-1][j+v[i]]==1){
//减一个v[i]的情况
dp[i][j]=1;
}
else if(v[i]>=j&&dp[i-1][v[i]-j]==1){
//把v[i]放对面的情况
dp[i][j]=1;
}
}
}
int co=0;
for(int i=1;i<=m;i++){
if(dp[n][i]==1){
co++;
}
}
cout<<co;
return 0;
}
【问题描述】
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下
数列:
1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, …
给定一个正整数 N,请你输出数列中第一次出现
N 是在第几个数?
【输入格式】
输入一个整数 N。
【输出格式】
输出一个整数代表答案。
【样例输入】
6
【样例输出】
13
思路
没啥思路,4000以下纯暴力,( 多了会超时 可能或许5000也行,但是我没冒险 )4000以上当做n在第n+1排的第二个处理,反正质数肯定是满足的,其他数应该也有不少满足的 用等差数列前n项和公式就行,公差为1,Sn = n+(n*(n-1))/2
#include
#define ll long long
using namespace std;
int G[5005][5005];
int n;
int main()
{
cin>>n;
if(n>4000){
//或许能骗分
cout<<n+(n*(n-1))/2+2;
return 0;
}
G[1][1]=1;
for(int i=2;i<=n+1;i++){
G[i][1]=1;
for(int j=2;j<=i;j++){
G[i][j]=G[i-1][j]+G[i-1][j-1];
}
}
int now=0; //自增个数
for(int i=1;i<=n+1;i++){
for(int j=1;j<=i;j++){
now++;
if(n==G[i][j]){
//遇到第一个就是答案
cout<<now;
return 0;
}
}
//cout<
}
return 0;
}
【问题描述】
给定序列 (a1, a2, · · · , a**n) = (1, 2, · · · , n),即 a**i
= i。
小蓝将对这个序列进行 m 次操作,每次可能是将 a1, a2, · · · , aqi 降序排列,
或者将 aqi , aqi+1, · · · , a**n 升序排列。
请求出操作完成后的序列。
【输入格式】
输入的第一行包含两个整数 n, m,分别表示序列的长度和操作次数。
接下来 m 行描述对序列的操作,其中第 i 行包含两个整数 p**i, q**i 表示操作
类型和参数。当 p**i = 0 时,表示将 a1, a2, · · · , aqi 降序排列;当 p**i = 1 时,表示
将 aqi , aqi+1, · · · , a**n 升序排列。
【输出格式】
输出一行,包含 n
个整数,相邻的整数之间使用一个空格分隔,表示操作
完成后的序列。
【样例输入】
3 3
0 3
1 2
0 2
【样例输出】
3 1 2
思路
没有思路…只能用sort纯模拟 能过60%的点…
#include
#define ll long long
using namespace std;
int a[100005];
int n,m;
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++){
a[i]=i;
}
for(int i=1;i<=m;i++){
int p,q;
scanf("%d%d",&p,&q);
if(p==0){
sort(a+1,a+1+q,cmp);
}
else {
sort(a+q,a+1+n);
}
}
for(int i=1;i<=n;i++){
if(i!=1){
//不知道会不会卡空格
cout<<" ";
}
cout<<a[i];
}
return 0;
}
【问题描述】
给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,
当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。
两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括
号。
例如,对于括号序列 (((),只需要添加两个括号就能让其合法,有以下几
种不同的添加结果:()()()、()(())、(())()、(()()) 和 ((()))。
【输入格式】
输入一行包含一个字符串 s,表示给定的括号序列,序列中只有左括号和
右括号。
【输出格式】
输出一个整数表示答案,答案可能很大,请输出答案除以
1000000007 (即
109 + 7) 的余数。
【样例输入】
((()
【样例输出】
5
思路
没思路,也没时间想。 草率了,空了,样例都没输出一下,复制出来纯粹是为了 给有兴趣的人看一下
其他感觉还行,算是正常发挥了吧,能做的都做了,不会的也依旧不会,最气人的是第一第二题都错了!!!!今年的体验感还行,明年继续。