蓝桥杯 2022 省 B

Posted zrzring

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯 2022 省 B相关的知识,希望对你有一定的参考价值。

蓝桥杯 × DP杯 √

C - 刷题统计

https://www.luogu.com.cn/problem/P8780

签到题,先大跨步对每周的题数取模,然后暴力计算最后一周需要做的题。

int main() 
	i64 a = read(), b = read(), n = read();
	i64 ans = n / (5 * a + 2 * b) * 7, rest = n % (5 * a + 2 * b);
	for (int i = 1; i <= 5; i++) 
		if (rest <= 0) break; rest -= a; ans++;
	
	for (int j = 1; j <= 2; j++) 
		if (rest <= 0) break; rest -= b; ans++;
	
	printf("%lld\\n", ans);
	return 0;

D - 修建灌木

https://www.luogu.com.cn/problem/P8781

签到题,考虑每棵灌木需要等待的时间只有爱丽丝经过这棵灌木再从两边回来两种情况,取 \\(max\\) 即可。

int main() 
	int n = read();
	for (int i = 1; i <= n; i++) 
		printf("%d\\n", 2 * std::max(i - 1, n - i));
	
	return 0;

E - X 进制减法

https://www.luogu.com.cn/problem/P8782

进制决定了该位之后的数的系数,为了使最后的结果最小,那么每一位的进制就要尽量小。

const int mod = 1e9 + 7;

int main() 
	int M = read(), n1, n2;
	n1 = read(); int a[n1 + 1]; memset(a, 0, sizeof(a));
	for (int i = n1; i >= 1; i--) a[i] = read();
	n2 = read(); int b[n2 + 1]; memset(b, 0, sizeof(b));
	for (int i = n2; i >= 1; i--) b[i] = read();
	int n = std::max(n1, n2);
	i64 mul[n + 1]; mul[0] = 1;
	for (int i = 1; i <= n; i++) 
		if (i > n1) 
			mul[i] = mul[i - 1] * std::max(2, b[i] + 1) % mod; continue;
		
		if (i > n2) 
			mul[i] = mul[i - 1] * std::max(2, a[i] + 1) % mod; continue;
		
		mul[i] = mul[i - 1] * std::max(2, std::max(a[i] + 1, b[i] + 1)) % mod;
	
	i64 A = 0, B = 0;
	for (int i = 1; i <= n1; i++) A = (mul[i - 1] * a[i] + A) % mod;
	for (int i = 1; i <= n2; i++) B = (mul[i - 1] * b[i] + B) % mod;
	printf("%lld", (A - B + mod) % mod);
	return 0;

F - 统计子矩阵

https://www.luogu.com.cn/problem/P8783

考虑暴力,枚举子矩阵的对角线,然后用前缀和优化计算,设 \\(n\\)\\(m\\) 同级,复杂度 \\(O(n^4)\\)

如何优化?一维空间下我们可以通过双指针达到 \\(O(n)\\) 的复杂度,二维的话我们可以对某一维的端点进行枚举,确定之后即可对其降维,另一维使用双指针进行计算即可,复杂度 \\(O(n^3)\\)

int main() 
	int n = read(), m = read(), k = read();
	i64 a[n + 1][m + 1];
	for (int i = 1; i <= n; i++) 
		for (int j = 1; j <= m; j++) a[i][j] = read();
	
	for (int i = 1; i <= n; i++) 
		for (int j = 1; j <= m; j++) 
			a[i][j] += a[i - 1][j];
		
	
	i64 ans = 0;
	for (int l = 1; l <= n; l++) 
		for (int r = l; r <= n; r++) 
			int now = 0, x = 1;
			for (int i = 1; i <= m; i++) 
				now += a[r][i] - a[l - 1][i];
				while (now > k) 
					now -= a[r][x] - a[l - 1][x]; x++;
				
				ans += i - x + 1;
			
		
	
	printf("%lld\\n", ans);
	return 0;

G - 积木画

https://www.luogu.com.cn/problem/P8784

考虑每种状态只有可能是凸出一块,或者没有凸出,记 \\(f_i, 0\\) 为前 \\(i\\) 列填满的方案数,\\(f_i, k\\) 表示前 \\(i - 1\\) 列填满,第 \\(i\\) 列的第 \\(k\\) 行没填满的方案数,转移方程为

\\[\\beginaligned f_i, 0 &= f_i - 2, 0 + f_i - 1, 1 + f_i - 1, 2 + f_i - 1, 0 \\\\ f_i, 1 &= f_i - 1, 2 + f_i - 2, 0 \\\\ f_i, 2 &= f_i - 1, 1 + f_i - 2, 0 \\endaligned \\]

int main() 
	int n = read(), f[n][3];
	memset(f, 0, sizeof(f));
	f[0][0] = f[1][0] = 1;
	for (int i = 2; i <= n; i++) 
		f[i][0] = (1ll * f[i - 2][0] + f[i - 1][1] + f[i - 1][2] + f[i - 1][0]) % mod;
		f[i][1] = (1ll * f[i - 1][2] + f[i - 2][0]) % mod;
		f[i][2] = (1ll * f[i - 1][1] + f[i - 2][0]) % mod;
	
	printf("%d\\n", f[n][0]);
	return 0;

I - 李白打酒加强版

https://www.luogu.com.cn/problem/P8786

\\(f_i, j, k\\) 表示李白经历了 \\(i\\) 个店,\\(j\\) 个花后剩 \\(k\\) 斗酒的方案数

\\[f_i, j, k = f_i - 1, j, k / 2 + f_i, j - 1, k + 1 \\]

\\(k\\) 为奇数则没有前一项。

const int mod = 1e9 + 7;

int main() 
	int n = read(), m = read(), f[n + 1][m + 1][2 * m + 1];
	memset(f, 0, sizeof(f));
	f[0][0][2] = 1;
	for (int i = 0; i <= n; i++) 
		for (int j = 0; j <= m; j++) 
			for (int k = 0; k <= m; k++) 
				if (i && k % 2 == 0) f[i][j][k] += f[i - 1][j][k / 2], f[i][j][k] %= mod;
				if (j) f[i][j][k] += f[i][j - 1][k + 1], f[i][j][k] %= mod;
			
		
	
	printf("%d\\n", f[n][m - 1][1]);
	return 0;

J - 砍竹子

https://www.luogu.com.cn/problem/P8787

考虑每个竹子砍一次 \\(\\Big\\lfloor\\sqrt\\lfloor\\fracH2\\rfloor + 1\\Big\\rfloor\\leq \\lfloor\\fracH2\\rfloor\\),于是一个竹子最多 \\(\\log_2 H\\) 次就能被砍完,若不存在魔法暴力砍竹子也可以用 \\(O(n \\log_2 H)\\) 复杂度计算次数。

考虑使用魔法的最优解,我们希望每次砍竹子,都能将连续的,长度相同的竹子一次性砍掉。

我们可以考虑维护相同高度且连续的竹子的区间,由于竹子不会长高,所以我们每次砍掉最高的竹子一定是最优的,砍掉当前最高的竹子后,判定其和旁边的竹子高度是否相同,若相同则合并这两个区间,我们可以用堆维护当前的竹子,并记录其区间信息。

为了能快速找到其相邻的区间,我们可以第二关键字设置为左端点或右端点,这样我们再次取堆顶即可判定是否合并。

int main() 
	int n = read(); i64 a[n + 1];
	for (int i = 1; i <= n; i++) a[i] = read();
	i64 ans = 0;
	while (1) 
		i64 max = 0; int l = 0;
		for (int i = 1; i <= n; i++) 
			if (a[i] > max) max = a[i], l = i;
		
		if (max == 1) break; int r = l;
		while (r < n && a[r + 1] == a[l]) r++;
		ans++;
		for (int i = l; i <= r; i++) a[i] = sqrt(a[i] / 2 + 1);
	
	printf("%lld", ans);
	return 0;

第七届蓝桥杯大赛个人赛省赛(软件类)B组

3.凑算式


     B      DEF
A + --- + ------- = 10
     C      GHI
     
(如果显示有问题,可以参见【图1.jpg】)
   
这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。

比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。

这个算式一共有多少种解法?

注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。

 

这道有点坑吧,尤其对于我这种看题不仔细的,看到题是想着"/"这个运算是整数的,啪啪敲了代码一算两万多,想着也没毛病,可是答案说是29,找了半天看样例时发现了这里取商的值是小数......

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <math.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int vis[100];
int a[100], cnt;

void DFS(int t)
{
    if(t==9)
    {
        int f=1;
        for(int i=0; i<=8; i++)
        {
            if(a[i]==0)
            f=0;
        }
        if(f==1&&fabs((1.0*a[0]+1.0*a[1]/a[2]+1.0*(a[3]*100+a[4]*10+a[5])/(a[6]*100+a[7]*10+a[8]))-10)<1e-10)
        {
            cnt++;
        }
        return;
    }
    for(int i=1; i<=9; i++)
    {
        if(!vis[i])
        {
            a[t]=i;
            vis[i]=1;
            DFS(t+1);
            vis[i]=0;
            a[t]=0;
        }
    }
}

int main(int argc, char** argv) {
    cnt=0;
    for(int i=1; i<=9; i++)
    {
        memset(vis, 0, sizeof(vis));
        memset(a, 0, sizeof(a));
        vis[i]=1;
        a[0]=i;
        DFS(1);
    }
    printf("%d\\n", cnt);
    return 0;
}

 

以上是关于蓝桥杯 2022 省 B的主要内容,如果未能解决你的问题,请参考以下文章

《蓝桥杯真题》:2022年单片机省赛(第十三 / 13届第一场)

《蓝桥杯真题》:2022年单片机省赛(第十三 / 13届第一场)

《蓝桥杯真题》:2022单片机省赛第二场(第十三 / 13届第二场)

《蓝桥杯真题》:2022单片机省赛第二场(第十三 / 13届第二场)

《蓝桥杯真题》:2022单片机省赛第二场(第十三 / 13届第二场)

洛谷P8661 [蓝桥杯 2018 省 B] 日志统计 C语言/C++