2020年蓝桥杯省赛 C++ A组(第一场)

本文提供了几个编程题目,涉及跑步训练时间计算、合并检测策略分析以及口罩的公平分配问题。每个问题都包含C++代码实现,利用数学和动态规划方法解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A.跑步训练

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+5;
int n=10000;
int res;
int main(){
	while(n>=600){
		n-=300;
		res+=2*60;
	}
	res+=n*60/600;
	cout<<res;
} 

B.合并检测(均值不等式 / 打表)

① 均值不等式

 ② 打表
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+5;
int n=10000;
int main(){
	for(int k=1;k<=100;k++){
		int g=(n+k/2)/k;//总组数 
		int p=min(g,int(n*0.01));//被感染组数(均匀分布) 
		cout<<k<<" "<<p*(k+1)+(g-p)<<endl;
	}
} 

C.分配口罩

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+5;
int w[]={9090400, 8499400, 5926800, 8547000, 4958200, 4422600, 5751200,
4175600, 6309600, 5865200, 6604400, 4635000, 10663400, 8087200, 4554000};
int check(int x){
	int a=0,b=0;
	for(int i=0;i<15;i++){
		if(x>>i&1) a+=w[i];
		else b+=w[i];
	}
	return abs(a-b);
} 
int main(){
	int res=0x3f3f3f3f;
	for(int i=0;i<1<<15;i++){
		res=min(res,check(i));
	}
	cout<<res;
} 

D.矩阵(DP)

        f[i][j] 表示前i个数顺序放置,且第一行放了j个数的合法方案数

① 保证右边比左边大,放置时需要从小到大顺序放置,即可满足

② 保证下边比上边大,如果将第i个数放到第二行,需要判断放置后第二行数的个数是否<=第一行数个数,如果不满足说明对于该列先放下边后放上边,不满足下边大于上边

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2055,mod=2020;
int f[N][N];
//f[i][j] 前i个数 第一行放了j个
//按顺序放,即先放左边再放右边,能保证右边大于左边
//第二行的个数<=第一行 保证先放上面再放下面,即下边比上边大 
int main(){
	f[0][0]=1;
	for(int i=1;i<=2020;i++){
		for(int j=0;j<=i;j++){
			//第一行 
			f[i][j]=(f[i][j]+f[i-1][j-1])%mod;
			//第二行 
			if(i-j<=j){
				f[i][j]=(f[i][j]+f[i-1][j])%mod;
			}
		}
	}
	cout<<f[2020][1010];
} 

E.完美平方数


F.解码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2055;
string s;
int main(){
	cin>>s;
	char c;
	for(int i=0;i<s.length();i++){
		if(isdigit(s[i])){
			for(int j=0;j<s[i]-'0'-1;j++){
				cout<<c;
			}
		}else{
			cout<<s[i];
			c=s[i];
		}
	}
} 

G.走方格(数字三角形DP)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2055;
int f[N][N];
int n,m;
int main(){
	cin>>n>>m;
	f[1][1]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(i%2==0&&j%2==0) continue;
			f[i][j]+=f[i-1][j];
			f[i][j]+=f[i][j-1];
		}
	}
	cout<<f[n][m];
} 

H.整数拼接(数位技巧)

        如果A和B组合的数X是K的倍数,则有X=A*10^z+B(z为B的位数),且A*10^z %K==(-B%K+K)%K,即两数模K的余数互补,那么我们可以考虑将模K相等的数的个数记录下来。

        对于每个数A,枚举其*10的位数,并根据模K的余数记录个数,进行预处理。对于每个数B,其作为低位时,与其匹配的高位数的个数为mp[z][(-B%K+K)%K](z为B的位数)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5;
int n,k;
int w[N]; 
int mp[11][N];
//mp[i][j]   x*10^i %k == j 的x的数量
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&w[i]);
		int t=w[i]%k;
		for(int j=0;j<=10;j++){
			mp[j][t]++;
			t=t*10%k;
		}
	}
	ll res=0;
	for(int i=1;i<=n;i++){
		int t=w[i],d=0;
		while(t) t/=10,d++;
		int nd=(k-w[i]%k)%k;
		res+=mp[d][nd];
 		//判断是否包含w[i]和w[i] 
		int tw=w[i]%k;
		while(d--) tw=tw*10%k;
		if(tw==nd) res--;
	}
	cout<<res;
} 

I.超级胶水(规律分析)

        最终的结果等于每两个石子之间都相乘的和

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5;
int n;
int w[N]; 
ll sum[N];
ll res;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&w[i]);
		sum[i]=sum[i-1]+w[i];
	}
	for(int i=1;i<=n;i++){
		res+=(ll)w[i]*(sum[n]-sum[i]);
	}
	printf("%lld",res);
} 

J.网络分析(并查集高阶操作)

        做法一:每次合并时,如果这两个点不在同一连通块,则构造一个新点,使这个新点成为合并后的根节点,同时从根节点向两个点连边。最后从新点中的根节点fa开始DFS,将fa的权值传递给子节点

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e4+5,M=N<<2;
int n,m;
int p[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b){
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
int f[N];
int new_node;
int find(int x){
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
void dfs(int u,int fa){
	f[u]+=f[fa];
	for(int i=h[u];~i;i=ne[i]){
		int j=e[i];
		dfs(j,u);
	}
}
int main(){
	cin>>n>>m;
	new_node=n+1;
	memset(h,-1,sizeof h);
	for(int i=1;i<=2*n;i++) p[i]=i;
	while(m--){
		int c,a,b;cin>>c>>a>>b;
		if(c==1){
			a=find(a),b=find(b);
			if(a!=b){
				p[a]=p[b]=new_node;
				add(new_node,a);
				add(new_node,b);
				new_node++;
			}
		}else{
			a=find(a);
			f[a]+=b;
		}
	}
	for(int i=n+1;i<new_node;i++){
		if(p[i]==i) dfs(i,0);
	}
	for(int i=1;i<=n;i++){
		cout<<f[i]<<" ";
	}
} 

        做法二:维护到根节点的权值,一个点的权值等于从该点到根节点的路径上的所有点的权值之和。合并两个根节点时,例如将a合并到b上,为了保证并查集中的点之前的权值不受影响,需要将a的权值减去b的权值抵消,再将a的父节点更新为b. 最后查询时,对于根节点则直接输出权值,非根节点的权值等于该点权值加上根节点的权值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e4+5,M=N<<1;
int n,m;
int p[N];
int d[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b){
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
int find(int x){//x是根节点 或 x的父节点是根节点 则不压缩 
	if(p[x]!=x&&p[p[x]]!=p[x]){
		int fa=find(p[x]);
		d[x]+=d[p[x]];
		p[x]=fa;
	}
	return p[x];
}
int main(){
	cin>>n>>m;
	memset(h,-1,sizeof h);
	for(int i=1;i<=n;i++) p[i]=i;
	while(m--){
		int c,a,b;cin>>c>>a>>b;
		if(c==1){
			a=find(a),b=find(b);
			if(a!=b){
				d[a]-=d[b];
				p[a]=b;
			}
		}else{
			a=find(a);
			d[a]+=b;
		}
	}
	for(int i=1;i<=n;i++){
		if(find(i)==i) cout<<d[i]<<" ";
		else cout<<d[i]+d[find(i)]<<" ";
	}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Vic.GoodLuck

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

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

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

打赏作者

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

抵扣说明:

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

余额充值