[蓝桥杯2021初赛] B组

一、[蓝桥杯2021初赛] 卡片

小蓝有很多数字卡片,每张卡片上都是数字0 到9。
小蓝准备用这些卡片来拼一些数,他想从1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从1 拼到多少。
例如,当小蓝有30 张卡片,其中0 到9 各3 张,则小蓝可以拼出1 到10,但是拼11 时卡片1 已经只有一张了,不够拼出11。
现在小蓝手里有0 到9 的卡片各2021 张,共20210 张,请问小蓝可以从1拼到多少?
提示:建议使用计算机编程解决问题。

#include<iostream>
using namespace std;
int num[11];
int main()
{
	int i, j, k;
	for (int i = 1;; i++)
	{
		j = i;
		while (j)
		{
			k = j % 10;
			num[k]++;
			j /= 10;
			if (num[k] == 2022)
			{
				printf("%d", i-1);
				return 0;
			}
		}
	}
}

二、 [蓝桥杯2021初赛] 直线

在平面直角坐标系中,两点可以确定一条直线。
如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。
给定平面上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) 之间的整数的点。
请问这些点一共确定了多少条不同的直线。

#include<iostream>
#include<string.h>
#include<set>
using namespace std;
struct node {
	double x, y;
}p[25*25];
double a[1000][1000];
typedef pair<double, double> PDD;
set<PDD> s;
int main()
{
	int m = 20, n = 21;
	int count = 0;
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			p[count].x = i;
			p[count].y = j;
			count++;
		}
	}
	for (int i = 0; i < count; i++)
	{
		for (int j = 0; j < count; j++)
		{
			if (p[i].x == p[j].x || p[i].y == p[j].y)
				continue;
			double k = (p[j].y - p[i].y) / (p[j].x - p[i].x);
			double b = (p[j].x * p[i].y - p[j].y * p[i].x) / (p[j].x - p[i].x);
			s.insert({ k,b });
		}
	
	}
	cout <<m+n+s.size() << endl;
}

三、[蓝桥杯2021初赛] 货物摆放

小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有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 位数字)时,总共有多少种
方案?
提示:建议使用计算机编程解决问题。

#include<iostream>
#include<math.h>
using namespace std;
int main()
{
	long long count = 0;
	long long a[5000];
	long long n = 2021041820210418;
	for (int i = 1; i < sqrt(n); i++)
	{
		if (n % i == 0)
		{
			a[++count] = i;
			if (i * i != n)a[++count] = n / i;
		}
	}
	long long ans = 0;
	for (int l = 1; l <= count; l++)
		for (int w = 1; w <= count; w++)
			for (int h = 1; h <= count; h++)
				if (a[l] * a[w] * a[h] == n)ans++;
	cout << ans;
	return 0;
}

四、 [蓝桥杯2021初赛] 路径

小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由2021 个结点组成,依次编号1 至2021。
对于两个不同的结点a, b,如果a 和b 的差的绝对值大于21,则两个结点之间没有边相连;
如果a 和b 的差的绝对值小于等于21,则两个点之间有一条长度为a 和b 的最小公倍数的无向边相连。
例如:结点1 和结点23 之间没有边相连;结点3 和结点24 之间有一条无向边,长度为24;
结点15 和结点25 之间有一条无向边,长度为75。
请计算,结点1 和结点2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。

#include<iostream>
#include<string.h>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define N 2025
int edge[N][N];
int d[N];
bool vis[N];
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
int lcm(int a, int b) { return a / gcd(a, b) * b; }
int main()
{
	memset(edge, INF, sizeof(d));
	for (int i = 1; i < N; i++)
	{
		edge[i][i] = 0;
		for (int j = i+1; j < N; j++)
		{
			int m = lcm(i, j);
			edge[i][j] = edge[j][i] = m;
		}
	}
	memset(d, INF, sizeof(d));
	memset(vis, 0, sizeof(vis));
	d[1] = 0;
	for (int i = 1; i < N; i++)
	{
		int x = 0;
		for (int j = 1; j < N; j++)if (!vis[j] && d[j] < d[x])x = j;
		vis[x] = 1;
		for (int j = max(1, x - 21); j <= min(N, x + 21); j++)
		{
			d[j] = min(d[j], d[x] + edge[x][j]);
		}
	}
	cout << d[2021] << endl;
	return 0;
}

五、[蓝桥杯2021初赛] 空间

小蓝准备用256MB 的内存空间开一个数组,数组的每个元素都是32 位二进制整数。
如果不考虑程序占用的空间和维护内存需要的辅助空间,请问256MB 的空间可以存储多少个32 位二进制整数?

#include<iostream>
using namespace std;
int main()
{
	cout << ((256 * 1024) * 1024) / 4 << endl;
}

六、[蓝桥杯2021初赛] 砝码称重

你有一架天平和N 个砝码,这N 个砝码重量依次是W1, W2, ... , WN。
请你计算一共可以称出多少种不同的重量?
注意砝码可以放在天平两边。

输入的第一行包含一个整数N。
第二行包含N 个整数:W1, W2, W3, ... , WN。
对于50% 的评测用例,1 ≤ N ≤ 15。
对于所有评测用例,1 ≤ N ≤ 100,N 个砝码总重不超过100000。
 

#include<iostream>
#define LL long long
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define reps(i, a, b) for(int i = a; i < b; i++) 
#define pre(i, a, b) for(int i = b; i >= a; i--)
using namespace std;

const int N = 110, M = 1e5 + 10;

int n, m;
int a[N];
int f[N][M];

int main()
{
	cin >> n;
	rep(i, 1, n) cin >> a[i], m += a[i];
	
	rep(i, 1, n)
		rep(j, 1, m)
		{
			if(a[i] == j) f[i][j] = 1;
			else f[i][j] = f[i - 1][j] | f[i - 1][abs(j - a[i])] | f[i - 1][j + a[i]];
		}
	
	int ans = 0;
	rep(i, 1, m)
		if(f[n][i]) ans++;
	
	cout << ans << endl;
	return 0; 
}

七、[蓝桥杯2021初赛] 括号序列

给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法。
当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。
两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。
例如,对于括号序列(((),只需要添加两个括号就能让其合法
有以下几种不同的添加结果:()()()、()(())、(())()、(()()) 和((()))。

输入一行包含一个字符串s,表示给定的括号序列,序列中只有左括号和右括号。
对于40% 的评测用例,|s| ≤ 200。
对于所有评测用例,1 ≤ |s| ≤ 5000。

输出一个整数表示答案,答案可能很大,请输出答案除以1000000007

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;

typedef long long LL;
const int MOD=1000000007;
const int N=5010;
LL dp[N][N];
char str[N];
int len;
LL func()
{
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=1;i<=len;i++)
    {
        if(str[i]=='(')
        {
            for(int j=1;j<=len;j++)
            {
                dp[i][j]=dp[i-1][j-1];
            }
        }
        else
        {
            dp[i][0]=(dp[i-1][0]+dp[i-1][1])%MOD;
            for(int j=1;j<=len;j++)
            {
                 dp[i][j]=(dp[i-1][j+1] + dp[i][j-1])%MOD;
            }
        }
    }
    for(int i=0;i<=len;i++)
        if(dp[len][i]) return dp[len][i];
        return -1;
}
int main()
{
    scanf("%s",str+1);
    len=strlen(str+1);
    LL l=func();
    reverse(str+1,str+len+1);
    for(int i=1;i<=len;i++)
    {
        if(str[i]=='(') str[i]=')';
        else str[i]='(';
    }
    LL r=func();
    cout<<l*r%MOD;
    return 0;
}

八、[蓝桥杯2021初赛] 时间显示

小蓝要和朋友合作开发一个时间显示的网站。
在服务器上,朋友已经获取了当前的时间,用一个整数表示。
值为从1970 年1 月1 日00:00:00 到当前时刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。
小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。

输入第一行包含正整数T,表示存在T组测试数据,T不超过1000。
接下来T行,每行一个正整数表示时间。时间不超过10^18。

输出T行,每行按照如下格式:
输出时分秒表示的当前时间,格式形如HH:MM:SS
其中HH 表示时,值为0 到23,MM 表示分,值为0 到59,SS 表示秒,值为0 到59。
时、分、秒不足两位时补前导0。

#include<iostream>
using namespace std;
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		long long time;
		cin >> time;
		time = time / 1000;
		long long  h = time / 3600;
		long long m = (time - h * 3600) / 60;
		long long s = ((time - h * 3600) - m * 60);
		h = h % 24;
		m = m % 60;
		s = s % 60;
		if (h < 10)cout << '0' << h << ':';
		else cout << h << ':';
		if(m<10)cout << '0' << m << ':';
		else cout << m << ':';
		if (s < 10)cout << '0' << s ;
		else cout << s ;
		cout << endl;
	}
}

九、[蓝桥杯2021初赛] 杨辉三角形

下面的图形是著名的杨辉三角形:


如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, ...
给定一个正整数N,请你输出数列中第一次出现N 是在第几个数?

输入包含T行,表示T组测试数据。T不超过10。
每行输入一个整数N,N不超过10^9。 

对于每组测试数据输出一行表示答案。

#include <iostream>
typedef long long ll;
using namespace std;
ll N;
ll C(int a, int b)
{
	ll res = 1;
	for (ll i = a, j = 1; j <= b; i--, j++)
	{
		res = res * i / j;
		if (res > N)
			return res;
	}
	return res;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
	cin >> N;
	for (int k = 16; k >= 0; k--)
	{
		ll l = 2 * k, r = max(N, l), mid;
		while (l <= r) {
			mid = l + (r - l) / 2;
			ll CC = C(mid, k);
			if (CC == N)
				break;
			else if (CC > N)
				r = mid - 1;
			else
				l = mid + 1;
		}
		if (C(mid, k) == N)
		{//第mid行、第k列的数就是N
			cout << (mid + 1) * mid / 2 + k + 1 << endl;
			break;
		}
	}
    }
	return 0;
}

十、[蓝桥杯2021初赛] 双向排序

给定序列(a[1], a[2], ... , a[n]) = (1, 2, ... , n),即a[i] = i。
小蓝将对这个序列进行m次操作,每次可能是将a[1], a[2], ... a[qi] 降序排列,或者将a[qi], a[qi+1], ... , a[n] 升序排列。
请求出操作完成后的序列。

输入的第一行包含两个整数n, m,分别表示序列的长度和操作次数。
接下来m行描述对序列的操作,其中第i行包含两个整数pi, qi 表示操作类型和参数。
当pi = 0 时,表示将a[1], a[2], ... a[qi] 降序排列;当pi = 1 时,表示将a[qi], a[qi+1], ... , a[n] 升序排列升序排列。
对于30% 的评测用例,n,m ≤ 1000;
对于60% 的评测用例,n,m ≤ 5000;
对于所有评测用例,1 ≤ n,m ≤ 100000, 0 ≤ ai ≤ 1,1 ≤ bi ≤ n。

输出一行,包含n个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。

#include <iostream>
#include <string.h>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 100010;

int n, m;
PII stk[N];
int ans[N];

int main()
{
    scanf("%d%d", &n, &m);
    int top = 0;
    while (m -- )
    {
        int p, q;
        scanf("%d%d", &p, &q);
        if (!p)
        {
            while (top && stk[top].x == 0) 
				q = max(q, stk[top -- ].y);
            while (top >= 2 && stk[top - 1].y <= q) 
			
				top -= 2;
            stk[ ++ top] = {0, q};
        }
        else if (top)
        {
            while (top && stk[top].x == 1) q = min(q, stk[top -- ].y);
            while (top >= 2 && stk[top - 1].y >= q) top -= 2;
            stk[ ++ top] = {1, q};
        }
    }
    int k = n, l = 1, r = n;
    for (int i = 1; i <= top; i ++ )
    {
        if (stk[i].x == 0) 
            while (r > stk[i].y && l <= r) ans[r -- ] = k -- ;
        else
            while (l < stk[i].y && l <= r) ans[l ++ ] = k -- ; 
        if (l > r) break;
    }
    if (top % 2)
        while (l <= r) ans[l ++ ] = k -- ;
    else
        while (l <= r) ans[r -- ] = k -- ;

    for (int i = 1; i <= n; i ++ )
        printf("%d ", ans[i]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值