第十三届蓝桥杯大赛软件赛省赛CC++大学B组

第十三届蓝桥杯大赛软件赛省赛CC++ 大学 B 组

1、九进制转十进制

在这里插入图片描述

计算器计算即可。2999+29+2。

2、顺子日期

在这里插入图片描述
简单的枚举一下2022年的日期即可,注意遇到20220123,判断为一个即可。

#include<iostream>

#define ll long long
using namespace std;
int ans=0;
int d[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	for(int i=1;i<=12;i++){
		for(int j=1;j<=d[i];j++){
			int date[]={2,i/10,i%10,j/10,j%10};
			for(int k=0;k<3;k++){
				if(date[k]+1==date[k+1]&&date[k+1]+1==date[k+2]){
					ans++;
					break;
				}
			}
		}
	}
	cout<<ans;
	return 0;
}

3、刷题统计

在这里插入图片描述
分析:

这一题我本来用的是cmath里的ceil函数,但是提交之后我发现只能过掉70%,并没有全部通过。
随后我手写了ceil函数的功能,然后就可以100%通过了。
后来我就发现ceil函数原型是float ceilf (float x); 题意是1e18,肯定就会出现精度问题了,真的要记住这问题了,遇到特大数尽量手心函数,不要用库函数,可能就会出现问题。

#include<iostream>
#include<cmath>
#define ll long long
using namespace std;
ll a,b,n;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>a>>b>>n;
	ll x=(5*a+2*b);
	ll y=(n/x);// 坐满了几周,7*y 
	ll z=(n%x);// 还剩的题数 
	if(z<=5*a){
		if(z%a==0){
			z=z/a;
		}else{
			z=z/a+1;
		}
		cout<<7*y+z;
	}else{
		if((z-5*a)%b==0){
			z=(z-5*a)/b;
		}else{
			z=(z-5*a)/b+1;
		}
		cout<<7*y+5+z;
	}
	return 0;
}

4、修建灌木

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这一题直接暴力模拟过程即可,对于案例n=3,我们模拟过程会发现一个规律,那就是在1~n中最高的树是对称的而且最高的树的值都是这两个对称位置步长的2倍。

#include<iostream>
#define ll long long
using namespace std;
int n;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	/*
		n=3
		未剪   修剪后 	位置
		111 -> 011      1
		122 -> 101 		2
			
		212 -> 210		3
		321 -> 301		2
		412 -> 012		1
		123 -> 103 		2
		214 -> 210		3		
		可以看到出现了循环情况,也就说从左向右和从右向左,的最大值是就是步长的2倍 
	*/
	for(int i=1;i<=n;i++){
		cout<<max(i-1,n-i)*2<<"\n";
	}
	return 0;
}

5、x进制减法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
没想到啊,感觉脑袋被踢了。

代码示例:

#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const ll mod = 1000000007,N = 1e5+10;
ll n,ma,mb,a[N],b[N],p[N];
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	// 从高位县向低位输入,避免造成位数不相同 
	cin>>ma;
	for(ll i=ma;i>=1;i--)cin>>a[i];
	cin>>mb;
	for(ll i=mb;i>=1;i--)cin>>b[i];
	/*
		x进制类比一下 十进制 
		比如 123 就是 1*10*10+2*10+3
		那么x进制的:
		每一位的进制:11 5 2
		每一位的数字:10 4 1
		那么这个x进制对应的十进制不就是:10*5*2+4*2+1 
	*/
	// A >= B 	
	// 进制: 11 5 2  
	// 10 4 0  10*5*2+4*2+0=108
	// 1  2 0  1*5*2+2*2+0=14   108-14=94
	// 所以说最小的数位上的进制应该就是a[i]和b[i]这个数位的值+1 
	// 也就是说正好要进位的时候能得到最小值
	// 我们就使用p[i]来储存每个位上应该是什么进制 
	for(ll i=1;i<=ma;i++){
		p[i]=max((ll)2,max(a[i],b[i])+1);
	}
	p[0]=1;
	ll ans=0;
	for(int i=ma;i>=1;i--){ 
		// 为什么需要ans+a[i]+b[i]就能计算这个结果了?
		// 我们可以用两个十进制的数写一下,我们会发现ans其实就是最高位上没减完的数,然后加到下一位上了
		ans=(ans+a[i]-b[i])*p[i-1]%mod;
	}
	cout<<ans;
	return 0;
}

6、统计子矩阵

在这里插入图片描述
在这里插入图片描述

分析:

我直接想到的就是二维前缀和解决这个问题,去拿区间的值和k判断即可。
写的时候运行的结果一直不对,后来才发现是公式记错了,所以说记公式很重要。
区间的形式求值得公式是:res=prefix[x2][y2]-prefix[x2][y1-1]-prefix[x1-1][y2]+prefix[x1-1][y1-1] 。
但是直接暴力解决的话,只能过70%,其它的超时。优化的方法自行搜索。

#include<iostream>
#include<cstring>
#define ll long long
#define pii pair<ll,ll>
using namespace std;
const int N = 5e2+10;
ll n,m,k,mp[N][N],prefix[N][N],ans=0;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n>>m>>k;
	memset(prefix,0,sizeof(prefix));
	memset(mp,0,sizeof(mp));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){	 
			cin>>mp[i][j];
			prefix[i][j]=prefix[i-1][j]+prefix[i][j-1]+mp[i][j]-prefix[i-1][j-1];
		}
	
	for(int x1=1;x1<=n;x1++){
		for(int y1=1;y1<=m;y1++){
			for(int x2=x1;x2<=n;x2++){
				for(int y2=y1;y2<=m;y2++){
					// s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]
					ll res=prefix[x2][y2]-prefix[x2][y1-1]-prefix[x1-1][y2]+prefix[x1-1][y1-1];
					if(res<=k)ans++;
				}
			} 
		}
	}		
	cout<<ans;
	return 0;
}

7、积木画

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
递推思想。看了也不太懂,可以看看这个博客,讲的很清晰。
请点击:详细题解博客

#include <iostream>
using namespace std;
const int N = 1e7+10, mod = 1e9+7;
using ll = long long;
ll res[N];
int main(){
    int n;
    cin >> n;
    res[0] = 1;
    ll sum = 0;
    for(int i = 1, j = -2 ; i <= n ; ++i, ++j){
        res[i] = res[i-1];
        if(i >= 2) res[i] += res[i-2], res[i] %= mod;
        if(j >= 0) sum += res[j], sum %= mod;
        res[i] += sum << 1, res[i] %= mod;
    }
    cout << res[n];
    return 0;
}

8、扫雷

在这里插入图片描述
在这里插入图片描述
简单的枚举判断一下就行了。

#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int N = 105;
int n,m; 
int mp[N][N],ans[N][N];
int dx[]={0,0,1,-1,1,-1,1,-1};
int dy[]={1,-1,0,0,1,-1,-1,1};
bool isnmp(int x,int y){
	return x<0||x>=n||y<0||y>=m;
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n>>m;
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			cin>>mp[i][j];
	memset(ans,'0',sizeof(ans));
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(mp[i][j]==1){
				ans[i][j]=9;	
			}else{
				int rs=0;
				for(int k=0;k<8;k++){
					int nx=i+dx[k],ny=j+dy[k];
					if(isnmp(nx,ny))continue;
					if(mp[nx][ny]==1){
						rs++;
					}
				}
				ans[i][j]=rs;
			}
		}
	}	
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++)
			cout<<ans[i][j]<<" ";
		cout<<"\n";
	}
	return 0;
}

9、李白打酒加强版

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
遇到这一种给你n,m个数,然后有一些条件,在这些条件的情况,去求特定答案的解,一般都是最多/最少的数量。
这种题都需要使用递推的思想,因为中间的过程肯定有很多个我们直接·去判断寻找那肯定是不可能的,所以我们要总结规律,暴力的解法就是使用搜索层层递进,如果是答案的话那么就返回,也可以剪枝提高效率,或者找到规律总结状态转移方程使用动态规划。

#include<iostream>
#include<cstring> 
#define ll long long
using namespace std;
const int p = 1e9+7,N = 105;
ll dp[N][N][N];
//表示当前酒的数量,遇到店的数量,遇到花的数量 
ll dfs(int now,int n,int m){
	if(n<0||m<0||now<0)return 0;
	if(m<now)return 0;//因为遇到花要喝酒 
	if(m==1)return now==1&&n==0;// 最后遇到花的情况 
	if(dp[now][n][m]!=-1)return dp[now][n][m];// 记忆化搜索 
	dp[now][n][m]=(dfs(now*2,n-1,m)%p+dfs(now-1,n,m-1)%p)%p;
	return dp[now][n][m];
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n,m;cin>>n>>m;
	memset(dp,-1,sizeof(dp));
	dfs(2,n,m);
	cout<<dp[2][n][m];
	return 0;
}

10、砍竹子

在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N=2e5+10,M=10;
ll a[N][M],s[N],ans;
ll sqr(ll x){//sqrt只适用于int,所以要自己写一个函数
    ll ans=0,l=1,r=1e9;
	while(l<r){
		ll mid=(l+r)>>1;
		if(mid*mid<=x){
			l=mid+1;
		}else{
			r=mid;
		}
	}
    return l-1;
}
int main()
{
	int n;cin>>n;
	ll x=0;
    for(int i=0;i<n;i++){   
    	int y=0;
        cin>>x;
        while(x>1){
            s[++y]=x;
            x=sqr(x/2+1);
        }
        ans+=y;
        for(int j=0,k=y;k;j++,k--)a[i][j]=s[k];
    }
    // 检查相邻的数是否相等,若相等则操作次数减1
    for(int j=0;j<M;j++)
		for(int i=1;i<n;i++)
			if(a[i][j]&&a[i][j]==a[i-1][j])ans--; 
    cout<<ans;
    return 0;
}
  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

席万里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值