蓝桥杯2022B组省赛c++(蓝桥杯备战)

今天是2023年4月6日,今天应该是蓝桥杯考前的最后一次刷题了,明天课是真的恶心,晚上还有课,本想逃课的去机房刷题的,但自己还有一节晚自习没有上,明天还有场小白月赛,月赛应该大不了了,去机房也肯定是去不成的了,那么今天晚上总结总结吧。

首先说一说自己的做2022年题的感想吧,我只想说填空题是真的少,dp题我是真的不会!!!虽然我dp在牛客刷了将近40道题,但自己还是不会...言归正传还是写题解吧。

A:

简单的进制转换,但sb的我做错了,答案为2*9^0+0*9^1+2*9^2+2*9^3=1478

B

这题在纸上列举一下即可,但sb的我又做错了!!!

2022012(0-9):10

20221012:1

20221123:1

20221230:1

20221231:1

一共14种

C:

需要注意n的范围要开long long int,如果枚举天数,数据范围将太大会超时,所以需要枚举优化

设sum为每一整周刷题的数目,用n/sum得到的就是需要刷题的整周数,然后在从星期一开始遍历;最后结果为7*(n/sum)+time;

代码如下:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
int main(){
	ll a,b,n;
	cin>>a>>b>>n;
	ll time=0;
	ll now=5*a+2*b;
	ll num=n/now;
	ll sum=0;
	n=n%now;
	while(sum<n){
		time++;
		if(time%7==0||time%7==6){
			sum=sum+b;
		}else{
			sum=sum+a;
		}
	}
	printf("%lld\n",num*7+time);
	return 0;
}

 D:

 一道还算简单的思维题:但需要仔细看题,每天早上减枝,到晚上树枝会长高一亿亩

 

看图知答案(画的不咋地...)

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}
void print(__int128 num) {
	if (num) {
		print(num / 10);
		putchar(num % 10 + '0');
	}
}
int a[10005];
int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		a[i] = max((n - i) * 2, (i - 1) * 2);
	}
	for (int i = 1; i <= n; i++) {
		printf("%d\n", a[i]);
	}


	return 0;
}

 E:

 

一直搞不懂题目上321咋转换成65的,一直受2进制的影响,(321)10=3*8^2+2^10^1+1*2^0

其实不是这样...321中的3是由第二位来的,2是由第一位来的‘

所以321=(3*10+2)*2+1=65

本题还采用了贪心算法,要使得A-B最小即A和B的每一位都为最小进制,自我感觉..

但是要注意的是,用数组存储A和B的每一位的时候要从后往前存储,否则会导致错位,举个例子,A 为 321,B为25,如果正着存储A的3和B的2是一位,A的2和B的5是一位,就错位了。

代码如下:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}
void print(__int128 num) {
	if (num) {
		print(num / 10);
		putchar(num % 10 + '0');
	}
}
ll mod = 1000000007;
ll a[100005];
ll b[100005];
ll c[100005];
int main() {
	int n;
	scanf("%d", &n);
	int ma, mb;
	scanf("%d", &ma);
	for (int i = ma; i >=1; i--) {//从后往前存储,因为如果a为10 4 0,b为8 2,如果从前往后存储的话,10和8代表同一位,而10却是第3位,8为第2位
		scanf("%lld", &a[i]);
	}
	scanf("%d", &mb);
	for (int i = mb; i >=1; i--) {
		scanf("%lld", &b[i]);
	}
	ll ans1 = 0;
	ll ans2=0;
	int maxn = max(ma, mb);
	for (int i = 1; i <= maxn; i++) {
		c[i]=max((ll)2,max(a[i],b[i])+1);	//贪心,要使a-b最小,即每一位都为这一位的最小进制	
	}
	for(int i=ma;i>=1;i--){//简单模拟
		ans1=(ans1*c[i]+a[i])%mod; 	 	
	}
	for(int i=mb;i>=1;i--){
		ans2=(ans2*c[i]+b[i])%mod;
	}
	
	printf("%lld\n", (ans1-ans2+mod)%mod);//一定要记得+mod在模mod,因为在模的过程中ans1可能小于ans2;

	return 0;
}

F:

采用暴力写法即枚举起点和端点,然后用二维前缀和,虽然会超时,但是可以骗分,但需要注意的是二维前缀和s[i][j]的i和j代表的是格子,而且i和j都要从1开始

代码如下:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}	
int n,m,num;
int a[505][505];
int s[505][505];
int main(){
	cin>>n>>m>>num;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
			s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];
		}
	}
	int ans;
	ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			for(int k=i;k<=n;k++){//
				for(int l=j;l<=m;l++){
					if((s[k][l]-s[i-1][l]-s[k][j-1]+s[i-1][j-1])<=num){//不要重复定义,上边定义了k为不超过的值,下面又写了层循环,真的服了我了啊
						ans++;
					}else{
						break;
					}
				}
			}
		}
	}
	printf("%d\n",ans);
	
	return 0;
}

可以将二维前缀和进行优化,即加上双指针:

 

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
int a[505][505];
int s[505][505];
int main(){
	ll n,m,K;
	cin>>n>>m>>K;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
			s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];
		}
	}
	ll ans=0;
	for(int i=1;i<=m;i++){
		for(int j=i;j<=m;j++){
			for(int p=1,q=1;q<=n;q++){
				while(p<=q&&s[q][j]+s[p-1][i-1]-s[p-1][j]-s[q][i-1]>K){
					p++;
				}
				if(p<=q){
					ans=ans+q-p+1;
				}
			}
		}
	}
	printf("%lld\n",ans);
	
	


	return 0;
}

除此之外还可以一维前缀和+双指针:

s[i][j]代表第j列前i行的和

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
int a[505][505];
int s[505][505];//s[i][j]表示第j列前i个数的前缀和
int main(){
	ll n,m,top;
	cin>>n>>m>>top;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
			s[i][j]=a[i][j]+s[i-1][j];
		}
	}
	ll ans=0;
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){
			ll sum=0;
			for(int l=1,r=1;r<=m;r++){
				sum=sum+s[j][r]-s[i-1][r];//-s[i-1][r]不是-s[i][r];!!!!
				while(l<=r&&sum>top){
					sum=sum-(s[j][l]-s[i-1][l]);
					l++;
				}
				if(l<=r&&sum<=top){
					ans=ans+r-l+1;
				}
			}
		}
	}
	printf("%lld\n",ans);


	return 0;
}

G:积木画

在这里插入图片描述

 

H:扫雷:

这题和李白打酒一样还是dp,但是状态表示和状态转移方程好难写啊,看了题解才会的,菜鸡表示好难!!!

状态表示:dp[i][0]表示前i行已经满了,i+1没有木块,dp[i]][1]表示前i行满了,i+1行有一个木块

 

a[i][0]=(a[i-1][0]+a[i-2][1]+a[i-2][0])%mod;(注意a[i-2][0]拼a[i][0]只有一种情况,就是两块木块横着放)
a[i][1]=(2*a[i-1][0]+a[i-1][1])%mod;

代码如下:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
ll a[10000005][4];//a[i][0]表示前i列已经满了,a[i][1]表示前i列已经满了,第i+1列有一个方格
int n;
ll mod=1000000007;
int main(){
	scanf("%d",&n);
	a[1][0]=1;
	a[1][1]=2;
	a[2][0]=2;
	a[2][1]=4;
	if(n<=2){
		printf("%lld\n",a[n][0]);
	}else{
		for(int i=3;i<=n;i++){
			a[i][0]=(a[i-1][0]+a[i-2][1]+a[i-2][0])%mod;
			a[i][1]=(2*a[i-1][0]+a[i-1][1])%mod;
		}
		printf("%lld\n",a[n][0]%mod); 
	}
	

	return 0;
}

 

在这里插入图片描述

 咖啡老师说的对,如果没思路,就暴力开始搜素,把火箭能炸到的炸雷入队列,虽然超时,但可以骗分

 

#include <bits/stdc++.h>
struct node
{
    int x,y,d;
} a[100000],p[100010];
int vis[100000],t,n;
long long juli(int x,int y,int xx,int yy)
{
    return (long long)((x-xx)*(x-xx)+(y-yy)*(y-yy));
}
int main()
{
    int i,j,m;
    scanf("%d%d",&n,&m);
    for(i=1; i<=n; i++)
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].d);
    for(i=1; i<=m; i++)
        scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].d);
 
    int l=0,r=m+1;
    while(++l<r)
    {
        for(i=1; i<=n; i++)
        {
            //用vis来记录是否已经入队
            if(vis[i]==0&&juli(p[l].x,p[l].y,a[i].x,a[i].y)<=(long long )p[l].d*p[l].d)//要是在范围内就加入队列变成排雷火箭
            {
                vis[i]=1;
                t++;
                p[r++]=a[i];
            }
        }
    }
    printf("%d",t);
    return 0;
}

正确做法:二分+搜索

设火箭的爆炸范围为r,坐标为(x,y,z),那么将炸雷的坐标按x从小到大排序,然后将x1<x-r和x1>x+r的排除

bfs和dfs都行

bfs:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
//二分+搜索
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}
void print(__int128 num) {
	if (num) {
		print(num / 10);
		putchar(num % 10 + '0');
	}
}
struct Node {
	ll x, y, r;
} a[50004], b[50004];
bool cmp(Node a, Node b) {
	return a.x < b.x;
}
int ans = 0;
int n, m;
double dis(ll x1, ll x2, ll y1, ll y2) {
	return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int vis[50005];
void bfs(int x, int y, int r) {
	queue<Node>q;
	q.push({x, y, r});
	while (!q.empty()) {
		Node u = q.front();
		q.pop();
		int left = 1;
		int right = n;
		int lmid, rmid;
		while (left <= right) { //确定左端点,
			int mid = (left + right) / 2;
			if (a[mid].x < u.x - u.r) {
				left = mid + 1;
			} else {
				if (a[mid].x == u.x - u.r) {
					break;
				} else {
					right = mid - 1;
				}
			}
		}
		lmid = left;
		left = 1, right = n;
		while (left <= right) { //确定右端点
			int	mid = (left + right) / 2;
			if (a[mid].x < u.x + u.r) {
				left = mid + 1;
			} else {
				if (a[mid].x == u.x + u.r) {
					break;
				} else {
					right = mid - 1;
				}
			}
		}
		rmid = right;
		for (int i = lmid; i <= rmid; i++) {
			if (vis[i] == 0 && dis(a[i].x, u.x, a[i].y, u.y) <= u.r) {
				ans++;
				vis[i] = 1;
				q.push({a[i].x, a[i].y, a[i].r});
			}
		}

	}
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%lld%lld%lld", &a[i].x, &a[i].y, &a[i].r);
	}
	for (int i = 1; i <= m; i++) {
		scanf("%lld%lld%lld", &b[i].x, &b[i].y, &b[i].r);
	}
	sort(a + 1, a + 1 + n, cmp);
	for (int i = 1; i <= m; i++) {
		bfs(b[i].x, b[i].y, b[i].r);
	}
	printf("%d\n", ans);
	return 0;
}

dfs:

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
//二分+搜索
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
struct Node{
	ll x,y,r;
}a[50004],b[50004];
bool cmp(Node a,Node b){
	return a.x<b.x;
}
int ans=0;	
int n,m;
double dis(ll x1,ll x2,ll y1,ll y2){
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int vis[50005];
void dfs(int x,int y,int r){
	int left=1;
	int right=n;
	int lmid,rmid;
	while(left<=right){//确定左端点,
		int mid=(left+right)/2;
		if(a[mid].x<x-r){
			left=mid+1;
		}else{
			if(a[mid].x==x-r){
				break;
			}else{
				right=mid-1;
			}
		}
	}
	lmid=left;
	left=1,right=n;
	while(left<=right){//确定右端点
	int	mid=(left+right)/2;
		if(a[mid].x<x+r){
			left=mid+1;
		}else{
			if(a[mid].x==x+r){
				break;
			}else{
				right=mid-1;
			}
		}
	}
	rmid=right;
	for(int i=lmid;i<=rmid;i++){
		if(vis[i]==0&&dis(a[i].x,x,a[i].y,y)<=r){
			ans++;
			vis[i]=1;
			dfs(a[i].x,a[i].y,a[i].r);
		}
	}	
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].r);
	}
	for(int i=1;i<=m;i++){
		scanf("%lld%lld%lld",&b[i].x,&b[i].y,&b[i].r);
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=m;i++){
		dfs(b[i].x,b[i].y,b[i].r);
	}
	printf("%d\n",ans);
	return 0;
}

I:李白打酒加强版:

在这里插入图片描述 我感觉dp最难的就是状态表示和状态转移方程,然后我就推不出,真的难受,看了答案之后就恍然大悟了;

dp[i][j][k]为遇到了i次店,j次花,还有k斗酒

因为最后一次遇到的是花,所以答案为dp[n][m-1][0]

当遇到店时,dp[i][j][k]+=dp[i-1][j][k/2]所以i>0而且k为偶数且不为0

当遇到花时,dp[i][j][k]+=dp[i][j-1][k+1](确保j>0)

初始化dp[0][0][2]=1

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<map>
#include<set>
#include <utility>
using namespace std;
typedef  long  long ll ;
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
void print(__int128 num) {
	if(num) {
		print(num/10);
		putchar(num%10+'0');
	}
}
ll mod=1000000007;
int n,m;
ll dp[105][105][105];//dp[i][j][k]遇到了i次店,j次花还有k斗酒
int main(){
	scanf("%d%d",&n,&m);
	dp[0][0][2]=1;
	for(int i=0;i<=n;i++){
		for(int j=0;j<=m-1;j++){
			for(int k=0;k<=m;k++){
				if(k%2==0&&i)dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k/2])%mod;
				if(j)dp[i][j][k]=(dp[i][j][k]+dp[i][j-1][k+1])%mod;
			}
		}
	}
	printf("%lld\n",dp[n][m-1][1]);
	


	return 0;
}

今天是2023.4.7了,明天就考试了,希望有个好结果吧,写完就睡了,有点累了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值