[蓝桥杯2022初赛]题解

  1. 九进制转十进制

很简单的题,直接计算即可。

进制是指数值表示中的一种方法,常见的进制有十进制、二进制、八进制、十六进制等。不同进制的数码数量不同,二进制只有 0 和 1 两个数码,八进制有 0 到 7 这八个数码,十进制有 0 到 9 这十个数码,而九进制则有 0 到 8 这九个数码。

在九进制中,每一位上的数码的权值分别为 9 的 n 次方,其中 n 为这一位数码的位数,从右向左依次递增。例如,在九进制数 2022 中,最低位的权值为 9^0=1,次低位的权值为 9^1=9,再次低位的权值为 9^2=81,最高位的权值为 9^3=729。

要将九进制数 2022 转换成十进制数,可以将每一位上的数码乘以相应的权值,然后将这些结果相加即可。例如,将最低位的数码 2 乘以权值 9^0=1,得到结果 2;将次低位的数码 2 乘以权值 9^1=9,得到结果 18;将再次低位的数码 0 乘以权值 9^2=81,得到结果 0;将最高位的数码 2 乘以权值 9^3=729,得到结果 1458。将这些结果相加,得到的结果就是将九进制数 2022 转换成十进制数的结果,即 1478。

在实现上,可以使用循环遍历九进制数的每一位,取出每一位上的数码,然后根据相应的权值计算出该位的十进制值,最后将这些十进制值相加即可。具体实现可以使用语言内置的函数pow()实现幂的计算,也可以使用循环实现幂的计算。

#include
#include
using namespace std;
int main()
{
    int n = 2022;  // 九进制数
    int ans = 0;
    int i = 0;
    while (n != 0)
    {
        int d = n % 10;  // 取出最低位的数字
        ans +=d * pow(9, i);  // 将最低位的数字转换为十进制并加到结果中
        n /= 10;  // 去掉最低位的数字
        i++;  // 计数器加一
    }
    cout << ans << endl;  // 输出转换后的十进制数
    return 0;
}
  1. 顺子日期

本题通过观察可以发现,前面的2022不用管,只需要看后面的月份日期即可,又因为月份不超过12,日期不超过31,通过分析可知,存在1123,0120~0129,1230,1231,1012一共14个顺子。

故输出14。

  1. 刷题统计

经分析得每周做题总数为5*a+2*b,故通过n/wsum(每周做题总数)算出刷了几周题,周数乘7。

然后分析剩下的题目几天能刷完,分情况在5天内能刷完以及5天刷不完。

#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
int main() 
{
    LL a, b, n, day=0,m,wsum;
    cin >> a >> b >> n;
    wsum = 5 * a + 2 * b;
    day += n / wsum * 7;
    if (n % wsum > 5 * a)
    {
        day += 5 + (n % wsum - 5 * a) / b;
        if (5 + (n % wsum - 5 * a) % b)
            day++;
    }
    else
    {
        day += (n % wsum) / a;
        if ((n % wsum) % a)
            day++;
    }
    cout << day;
    return 0;
}
  1. 修剪灌木

早上长,傍晚剪为0,每棵树最高长到max(这个树到左边的距离,这个数到右边的距离)*2

#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
int main() 
{
    int n, tree[10005] = {0};
    cin >> n;
    for (int i = 1; i <= (n + 1)/2; i++)
    {
        tree[i] = (n - i + 1) * 2 - 2;
        tree[n - i + 1] = tree[i];
    }
    for (int i = 1; i <= n; i++)
        cout << tree[i] << endl;
    return 0;
}
  1. X进制减法

每一位上的进制越小,最后的和才会大。所以枚举一遍 ab 数组。

#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const LL P = 1000000007;
LL a[100010], b[100010], c[100010], sum[100010], n, lena, lenb, ans1, ans2;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> lena;
    for (int i = lena; i >= 1; i--) cin >> a[i]; 
        cin >> lenb;
    for (int i = lenb; i >= 1; i--) cin >> b[i];
    LL maxlen = max(lena, lenb); 
    for (int i = maxlen; i >= 1; i--) c[i] = max(max(a[i], b[i]) + 1, (LL)(2));
    sum[1] = 1;
    for (int i = 2; i <= maxlen; i++) sum[i] = (c[i - 1] * sum[i - 1]) % P; 
    for (int i = lena; i >= 1; i--) ans1 = (ans1 + a[i] * sum[i]) % P;  
    for (int i = lenb; i >= 1; i--) ans2 = (ans2 + b[i] * sum[i]) % P;  
    cout << (ans1 - ans2 + P) % P; 
    return 0;
}
  1. 统计子矩阵

给定一个 N × M 的矩阵A,请你统计有多少个子矩阵(最小 1 × 1,最大 N × M) 满足:

子矩阵中所有数的和不超过给定的整数K?

ll n,m,k,a[505][505],cnt[505][505],ans;
int main(){
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%lld",&a[i][j]);
            cnt[i][j]=cnt[i-1][j]+a[i][j];//按列做的前缀和
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){//确定上边界和下边界,注意j从i开始枚举
            ll s=0;
            for(int l=1,r=1;r<=m;r++){///双指针模板
                s+=cnt[j][r]-cnt[i-1][r];//这里加的是一个用前缀和优化的区间
                while(s>k){
                    s-=cnt[j][l]-cnt[i-1][l];//减的当然也是区间
                    l++;
                }
                ans+=r-l+1;//把所有可以的答案加到ans里
            }
        }
    }
    cout<

7.积木画

小明最近迷上了积木画,有这么两种类型的积木,分别为 I 型(大小为 22 个单位面积) 和 L 型 (大小为 33 个单位面积):

[蓝桥杯2022初赛]题解_第1张图片

同时,小明有一块面积大小为 2×2×N 的画布,画布由 2×2×N 个 1×11×1 区域构成。小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式? 积木可以任意旋转,且画布的方向固定。

typedef long long ll;
ll p[4], q[4];
const int mod = 1e9 + 7;
int main() {
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);    
    int n;
    cin >> n;
    p[3] = 1;
    for(int i = 1; i <= n; i ++) {
        q[3] = (p[0] + p[1] + p[2] + p[3]) % mod;
        q[0] = p[3] % mod;
        q[1] = (p[0] + p[2]) % mod;
        q[2] = (p[0] + p[1]) % mod;
        for(int i = 0; i <= 3; i ++)
            p[i] = q[i];
    }
    cout << p[3];
    return 0;
}

8.扫雷

structboom{
	int x,y,r,id;
	boom(){}
	boom(int x,int y,int r,int id):
		x(x),y(y),r(r),id(id){}
}b[inf];
boolcmp(boom x,boom y){
	return x.yh[inf];
intpf(int x){return x*x;}
doubledis(int x,int y){
	returnsqrt(pf(b[x].x-b[y].x)+pf(b[x].y-b[y].y));
}
int fir[inf],nex[inf<<1],poi[inf<<1],cnt;
voidins(int x,int y){
	nex[++cnt]=fir[x];
	poi[cnt]=y;
	fir[x]=cnt;
}
bool vis[inf];
intmain(){
	n=re();m=re();
	for(int i=1;i<=n;i++)
	{
		b[i].x=re(),b[i].y=re(),b[i].r=re();
		bok[i]=b[i].x;b[i].id=i;
	}
	sort(bok+1,bok+n+1);
	boks=unique(bok+1,bok+n+1)-bok-1;
	for(int i=1;i<=n;i++)
	{
		int ls=lower_bound(bok+1,bok+boks+1,b[i].x)-bok;
		h[ls].push_back(b[i]);
	}
	for(int i=1;i<=boks;i++)
	{
		sort(h[i].begin(),h[i].end(),[](boom a,boom b)
		{
			return a.y0)
	{
		b[0].x=re(),b[0].y=re(),b[0].r=re();
		queueq;
		memset(vis,0,sizeof(vis));
		int bex=lower_bound(bok+1,bok+boks+1,b[0].x-b[0].r)-bok;
		int endx=upper_bound(bok+1,bok+boks+1,b[0].x+b[0].r)-bok;
		while(bex!=endx)
		{
			int bey=lower_bound(h[bex].begin(),h[bex].end(),boom(0,b[0].y-b[0].r,0,0),cmp)-h[bex].begin();
			int endy=upper_bound(h[bex].begin(),h[bex].end(),boom(0,b[0].y+b[0].r,0,0),cmp)-h[bex].begin();
			while(bey!=endy)
			{
				if(dis(0,h[bex][bey].id)

9.李白打酒加强版

话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒 2 斗。他边走边唱:

无事街上走,提壶去打酒。

逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店 N 次,遇到花 M 次。

已知最后一次遇到的是花,他正好把酒喝光了。

请你计算李白这一路遇到店和花的顺序,有多少种不同的可能?

注意:壶里没酒( 0 斗) 时遇店是合法的,加倍后还是没酒;但是没酒时遇花是不合法的。

int n, m;
int f[205][105][105];
intmain(){
	cin >> n >> m;
	f[0][0][2] = 1;
	for (int i = 0; i < n + m; i ++)
		for (int j = 0; j < m; j ++)
			for (int k = 0; k <= m; k ++)
				if (f[i][j][k]) {
					if (k > 0) f[i + 1][j + 1][k - 1] = (f[i + 1][j + 1][k - 1] + f[i][j][k]) % 1000000007;
					if (k <= 50) f[i + 1][j][k * 2] = (f[i + 1][j][k * 2] + f[i][j][k]) % 1000000007;
				}
	cout << f[n + m][m][0];
	return0;

10.砍竹子

这天,小明在砍竹子,他面前有 n 棵竹子排成一排,一开始第 i 棵竹子的高度为 hi.

他觉得一棵一棵砍太慢了,决定使用魔法来砍竹子。

魔法可以对连续的一段相同高度的竹子使用,假设这一段竹子的高度为H,

那么使用一次魔法可以把这一段竹子的高度都变为:

[蓝桥杯2022初赛]题解_第2张图片

其中 ⌊x⌋ 表示对 x 向下取整。

小明想知道他最少使用多少次魔法可以让所有的竹子的高度都变为1。

#define N 200005#define int long long#define For(i, j, n) for(int i = j ; i <= n ; ++i)int n, cnt, fa[N];
structnode{ 
	int h, p; 
	friendbooloperator < (node x, node y){
		if(x.h == y.h) return x.p < y.p;
		return x.h < y.h;
	}
}t, a[N];

inlineintfind(int x){ return fa[x] ^ x ? fa[x] = find(fa[x]) : x; }

signedmain(){
	scanf("%lld", &n);
	priority_queueq;
	For(i, 1, n) scanf("%lld", &a[i].h), a[i].p = fa[i] = i;
	For(i, 2, n) if(a[i].h == a[i - 1].h) fa[find(i)] = find(i - 1);
	For(i, 1, n) if(find(i) == i && a[i].h > 1) q.push(a[i]); 
	while(!q.empty()){
		t = q.top();
		q.pop();
		if(t.h == a[find(t.p - 1)].h) fa[find(t.p)] = find(t.p - 1);
		if(find(t.p) ^ t.p) continue;
		a[t.p].h = t.h = sqrt((int)(t.h / 2) + 1);
		if(t.h > 1) q.push(t);
		++cnt;
	}
	printf("%lld", cnt);
	return0;

你可能感兴趣的:(蓝桥杯)