第十四届蓝桥杯大赛软件赛国赛C/C++ 大学 B 组(部分题解)


1 子2023

思路:

  • 比较基础的线性dp

代码:

#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define fi first
#define se second
#pragma GCC optimize(2)
#pragma GCC optimize("inline")
typedef pair<int,int> PII;
const int N = 1e3+10, INF = 0x3f3f3f3f;
int n=2023,ans;
string s="";
int dp[3];
//dp[0]:当前位置之前"2"的个数
//dp[1]:当前位置之前"20"的个数
//dp[2]:当前位置之前:"202"的个数 

void solve(){
	for(int i=1;i<=n;i++) s+=to_string(i);
	for(int i=0;i<s.size();i++){
		if(s[i]=='2') dp[0]++,dp[2]+=dp[1]; //2,202
		else if(s[i]=='0') dp[1]+=dp[0];//20
		else if(s[i]=='3') ans+=dp[2];//202加上当前位置的3 
	} 
	cout<<ans; //5484660609
}

signed main(){
	int T=1;
//	IOS;
//	cin>>T;
    while(T--){
    	solve();
	} 
	return 0;
}

2 双子数

思路:

  • 欧拉筛求素数,然后枚举所有素数,找到满足条件的
  • 记得超出范围时要及时break,不然会爆long long

代码:

#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define fi first
#define se second
typedef pair<int,int> PII;
const int N = 5e6+10, INF = 0x3f3f3f3f;
int L=2333,R=23333333333333; 
int ans;
int prime[N],cnt;
bool isprime[N];
set<int> s;

void get_prime(){
	memset(isprime,1,sizeof(isprime));
	isprime[1]=0;
	for(int i=2;i<N;i++){
		if(isprime[i]) prime[++cnt]=i;
		for(int j=1;j<=cnt&&i*prime[j]<N;j++){
			isprime[i*prime[j]]=0;
			if(i%prime[j]==0) break;
		}
	}
}

void solve(){
	get_prime();
	for(int i=1;i<=cnt;i++){
		int res=prime[i]*prime[i]*prime[i+1]*prime[i+1];
		if(res>R) break; //及时break,不然会溢出long long!!!
		for(int j=i+1;j<=cnt;j++){
			int res=prime[i]*prime[i]*prime[j]*prime[j];
			if(res>=L&&res<=R) ans++;
			if(res>R) break;
		}
	}
	cout<<ans; //947293
}

signed main(){
	int T=1;
//	IOS;
//	cin>>T;
    while(T--){
    	solve();
	} 
	return 0;
}

3 班级活动

思路:

  • 认真读题,题目中说了“有且仅有一名同学”,也是就是说两两相同,每对数之间是不同的
  • 所以id个数大于2的部分都是要修改的,根据贪心的思想,我们更希望把这些多出的部分和单个的id来配对!
  • 所以分为两类,多出的部分sum1,和单个的sum2,比较那个大
  • sum1>=sum2,把多出的部分修改为和单个的id相同的id,然后把剩下的sum1全都修改
  • sum1<sum2,就把多出的部分修改为和单个的id相同的id,然后把剩下的sum2修改一半即可!

代码:

#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define fi first
#define se second
typedef pair<int,int> PII;
const int N = 1e5+10, INF = 0x3f3f3f3f;
int n,a[N],ans; 


void solve(){
	cin>>n;
	map<int,int> mp;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		mp[a[i]]++;
	}
	int sum1=0,sum2=0,ans=0;
	for(auto i:mp){
		if(i.se>2) sum1+=i.se-2; //多出的
		else if(i.se<2) sum2++; //单个的
	}
	if(sum1>=sum2) sum1-=sum2,ans+=sum2+sum1;
	else sum2-=sum1,ans+=sum1,ans+=sum2/2;
	cout<<ans;
}

signed main(){
	int T=1;
//	IOS;
//	cin>>T;
    while(T--){
    	solve();
	} 
	return 0;
}

4 合并数列

思路:

  • 双指针,分别指向两个数组开头
  • 比较哪个大,小的那个就和后边的合并
  • 相等的话都同时右移

代码:

#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define fi first
#define se second
typedef pair<int,int> PII;
const int N = 1e5+10, INF = 0x3f3f3f3f;
int n,m,a[N],b[N];

void solve(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++) cin>>b[i];
	int cnt=0;
	int i=1,j=1,k1=1,k2=1;
	while(i<=n||j<=m){
//		cout<<i<<' '<<j<<' '<<a[i]<<' '<<b[j]<<endl;
		if(a[i]==b[j]){
			i+=k1; j+=k2;
			k1=1; k2=1;
		}
		else if(a[i]>b[j]){
			b[j]+=b[j+k2]; ++k2; ++cnt;
		}
		else{
			a[i]+=a[i+k1]; ++k1; ++cnt;
		}
	}
	cout<<cnt;
}

signed main(){
	int T=1;
//	IOS;
//	cin>>T;
    while(T--){
    	solve();
	} 
	return 0;
}

5 数三角

思路:

  • 以每个点为顶点,找出到顶点距离相等的点的集合,然后遍历这些点,满足条件答案加1,当然这里的满足条件指的是三点不共线
  • 用斜率来判断三点是否共线

代码:

#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define fi first
#define se second
typedef pair<int,int> PII;
const int N = 1e5+10, INF = 0x3f3f3f3f;
int n,ans;
vector<PII> arr;

double get_dist(int x1,int y1,int x2,int y2){ //两点间距离 
	return pow(x1-x2,2)+pow(y1-y2,2);
}

bool check(PII p1,PII p2,PII p3){
	if(p1.fi==p2.fi&&p1.fi==p3.fi) return true; //共线 
	double k1=(p1.se-p2.se)*1.0/(p1.fi-p2.fi);
	double k2=(p1.se-p3.se)*1.0/(p1.fi-p3.fi);
	return k1==k2; //斜率相等,共线 
}

void solve(){
	cin>>n;
	for(int i=0;i<n;i++){
		int x,y; cin>>x>>y;
		arr.push_back({x,y}); //记录坐标 
	} 
	for(int i=0;i<n;i++){
		map<int,vector<int>> mp; //存储到i号点距离相等的点的集合 
		for(int j=0;j<n;j++){
			if(i!=j){
				PII p1=arr[i],p2=arr[j];
				double d=get_dist(p1.fi,p1.se,p2.fi,p2.se);
				mp[d].push_back(j);
			}
		}
		for(auto t:mp){ //遍历所有的距离 
			vector<int> v=t.se; //到i号点距离相等的点 
			for(int j=0;j<v.size();j++){
				for(int k=j+1;k<v.size();k++){
					if(!check(arr[i],arr[v[j]],arr[v[k]])) ++ans;
				}
			}
		}
	}
	cout<<ans;
}

signed main(){
	int T=1;
//	IOS;
//	cin>>T;
    while(T--){
    	solve();
	} 
	return 0;
}

7 AB路线

思路:

  • bfs,每个点可以走多次

代码:

#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define fi first
#define se second
typedef pair<int,int> PII;
const int N = 1e3+10, INF = 0x3f3f3f3f;
int n,m,k,ans=-1;
char g[N][N];
bool st[N][N][11];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
struct node{
	int x,y,num,step;
};

void bfs(){
	queue<node> q;
	q.push({0,0,1,0});
	st[0][0][1]=1;
	while(q.size()){
		auto t=q.front(); q.pop();
		int x=t.x,y=t.y,num=t.num,step=t.step;
		if(x==n-1&&y==m-1){
			ans=step;
			break;
		}
		for(int i=0;i<4;i++){
			int tx=x+dx[i],ty=y+dy[i];
			if(tx<0||ty<0||tx>=n||ty>=m) continue;
			if(num==k){
				if(g[x][y]==g[tx][ty]||st[tx][ty][1]) continue;
				st[tx][ty][1]=1;
				q.push({tx,ty,1,step+1});
			}
			else if(g[tx][ty]==g[x][y]){
				if(st[tx][ty][num+1]) continue;
				st[tx][ty][num+1]=1;
				q.push({tx,ty,num+1,step+1});
			}
		}
	}
	
}

void solve(){
	cin>>n>>m>>k;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>g[i][j];
		}
	}
	bfs();
	cout<<ans;
}

signed main(){
	int T=1;
//	IOS;
//	cin>>T;
    while(T--){
    	solve();
	} 
	return 0;
}

8 抓娃娃

思路:

  • 判断线段是否被区间包含,只需要判断线段的中点是否在区间内,因为题目中已说线段的长度是小于等于区间长度的
  • 所以求出每个线段的终点,然后二分找到范围即可

代码:

#include<bits/stdc++.h>
using namespace std;

#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl '\n'
#define int long long
#define fi first
#define se second
typedef pair<int,int> PII;
const int N = 1e5+10, INF = 0x3f3f3f3f;
int n,m;
int a[N][2],b[N];


void solve(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int l,r; cin>>l>>r;
		l<<=1; r<<=1;
		a[i][0]=l,a[i][1]=r;
		b[i]=l+r>>1; //获取该线段中点 
	}
	sort(b+1,b+1+n);
	for(int i=1;i<=m;i++){
		int l,r; cin>>l>>r;
		l<<=1; r<<=1;
		int pos1=lower_bound(b+1,b+1+n,l)-b;
		int pos2=upper_bound(b+1,b+1+n,r)-b;
		cout<<pos2-pos1<<endl;
	} 
}

signed main(){
	int T=1;
//	IOS;
//	cin>>T;
    while(T--){
    	solve();
	} 
	return 0;
}
  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值