2023牛客寒假算法基础集训营6(题解及经验总结)

A 阿宁的签到题(简单题)

通过率:3035/3878

因代码打错wa了一发!!! 
注意else if的含义:若有一个满足条件,则后面的不再执行 !!!

赛场AC代码:

#include<cstdio>
#include<iostream>
#define int long long
using namespace std;

signed main(){
	int n;
	cin>>n;
	if(n>=1&&n<=7){
		cout<<"very easy";
	}else if(n>7&&n<=233){
		cout<<"easy";
	}else if(n>233&&n<=10032){
		cout<<"medium";
	}else if(n>10032&&n<=114514){
		cout<<"hard";
	}else if(n>114514&&n<=1919810){
		cout<<"very hard";
	}else{
		cout<<"can not imagine";
	}
	
	return 0;
} 

B 阿宁的倍数 

通过率:486/2909

因子、判质数

思路:定义一个桶u[N]来表示每个数的因数的个数,定义v[N]来表示截止到a[i]时,前i个数的因数a[i]的个数(前缀和),用总的因数u[a[i]]减去前i个数中因数a[i]的个数,即为第i个数之后因数a[i]的个数

AC代码:

#include<cstdio>
#include<iostream>
#define int long long
using namespace std;

const int N=200005;
int a[2*N],u[N],v[2*N];
signed main(){
	int n,q,op,x;
	cin>>n>>q; 
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j*j<=a[i];j++){
			if(a[i]%j==0){
				u[j]++;
				if(j*j!=a[i]){
					u[a[i]/j]++;
				}
			}
		}
		v[i]=u[a[i]];
	}
	for(int i=0;i<q;i++){
		cin>>op>>x;
		if(op==1){
			n++;
			a[n]=x;
			for(int j=1;j*j<=x;j++){
				if(x%j==0){
					u[j]++;
					if(j*j!=x){
						u[x/j]++;
					}
				}
			}
			v[n]=u[x];
		}else{
			cout<<u[a[x]]-v[x]<<endl;
		}
	}
	
	return 0;
} 

C 阿宁的大背包(简单题)

通过率:1884/5202

结论题!!!

杨辉三角???经典向量点积结论???

我的思路:直接构建形如:1 3 5 7 9...10 8 6 4 2的数组,该数组即能合成最大背包

赛场AC代码:

#include<cstdio>
#include<iostream>
#define int long long
using namespace std;

const int N=1005;
const int mod=1e9+7;
int a[N],b[N];
signed main(){
	int n;
	cin>>n;
	int j=1,k=n,t=n;
	for(int i=1;i<=n,j<=k;i++){
		if(i%2!=0){
			a[j]=i;
			b[j]=i;
			j++;
		}else{
			a[k]=i;
			b[k]=i;
			k--;
		}
	}
	while(n){
		for(int i=1;i<n;i++){
			a[i]=(a[i]+a[i+1])%mod;
		}
		n--;
	}
	cout<<a[1]<<'\n';
	for(int i=1;i<=t;i++){
		cout<<b[i]<<' ';
	}
	return 0;
} 

大的数尽量往中间放(因为他们能被加更多次),小的数往两边放!

D 阿宁的毒瘤题

通过率:867/3977

F 阿宁的二进制

通过率:1242/4361

时间不够,未通过。。。。

思路:操作数不多 在线回答 优先队列!!!

注意加深对优先队列的理解!!!

解法一:(最简解法)

思路:每输入一个a[i]都进行a[i]=f(a[i]),直到a[i]=1进行f(a[i])值不变为止,用数组b记录每次f(x)后的结果,最后对数组b进行排序,进行几次操作即输出第几大的值

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long 
using namespace std;

const int N=200005;
int a[N],b[1000000];
signed main(){
	int n,q,t=0;
	cin>>n>>q;
	for(int i=0;i<n;i++){
		cin>>a[i];
		while(a[i]>1){
			t++;
			b[t]=a[i];
			a[i]=__builtin_popcount(a[i]);	
		}
	}
	sort(b+1,b+1+t);
	while(q){
		int k;
		cin>>k;
		if(k>=t){
			cout<<1<<'\n';;
		}else{
			cout<<b[t-k]<<'\n';
		}
		q--;
	}
	return 0;
}

解法二:(优先队列)  

关于优先队列,传送门:c++优先队列(priority_queue)用法详解_吕白_的博客

关键: 头文件 #include<queue>

            定义 priority_queue<int> q    

            插入 push

            弹出 pop

            访问队头元素 top

            队列是否为空 empty

            返回队列内元素个数 size

            原地构造一个元素并插入队列 emplace

            交换内容 swap

#include<cstdio>
#include<iostream>
#include<queue>
#define int long long 
using namespace std; 

const int N=1000005;
int ans[N];
signed main(){
	int n,q;
	cin>>n>>q;
	priority_queue<int> qp;
	for(int i=0;i<n;i++){
		int a;
		cin>>a;
		qp.push(a);                   
	}
	for(int i=1;i<=N;i++){
		int x=__builtin_popcount(qp.top());
		qp.pop();
		qp.push(x);
		ans[i]=qp.top();
	}
	for(int i=0;i<q;i++){
		int x;
		cin>>x;
		cout<<ans[min(x,1000000ll)]<<endl;
	}
	return 0;
}

G 阿宁的整数配对(简单题)

通过率:2197/5610

睡醒之后还剩一个多小时,这道题思虑很清楚,一发入魂!

我的思路:先对数组排序,然后计算数组两端每端两个数的乘积,每次答案加上最大的一个值,直到取到所给的对数为止

赛场AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;

const int N=200005;
int a[N];
signed main(){
	int n,k;
	cin>>n>>k;
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	sort(a,a+n);
	int ans=0,i=0,j=n-1;
	while(k--){
		int x,y;
		x=a[i]*a[i+1];
		y=a[j]*a[j-1]; 
		if(x>=y){
			ans+=x;
			i+=2;
		}else{
			ans+=y;
			j-=2;
		}
	}
	cout<<ans;
	
	return 0;
} 

H 阿宁讨伐虚空(简单题)

通过率:2653/7202

赛场上未AC,WA了十发,最后心态崩了睡觉去了。。。。

因为代码里有一点小错误,始终都没有发现(把概率1.0当成了100.0).。。。。

修改后AC 代码:

#include<cstdio>
#include<iostream>
#define int long long
using namespace std;

signed main(){
	double x;
	double l,r;
	cin>>x;
	cin>>l>>r;
	if(x<=l){
		cout<<"0.00000000";
		return 0;
	}
	if(x>r){
		cout<<"1.00000000";
		return 0;
	}
	double ans;
	ans=(x-l)/(r-l+1);
	printf("%.8lf",ans);
	
	return 0;
} 

注意double和long double的区别和含义,f和lf的区别和含义!!!

最简单的写法:

#include<cstdio>
#include<iostream>
#define int long long
using namespace std;

signed main(){
	double x,l,r;
    cin>>x>>l>>r;
    cout<<min(max(0.0,x-l),r-l+1)*1.0/(r-l+1);
	
	return 0;
} 

I 阿宁前往沙城 

通过率:460/1950

思路:使用不定长数组g[i]来存储节点i所连接的节点,num[i]来存储节点1和节点i之间的路径长度,len[i]记录到达节点i经历的路径长度,vis[i]记录i点是否被访问过

#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#define int long long
using namespace std;

const int N=200005;
vector<int> g[N];//存储节点所连接的节点
queue<int> q;
int num[N];//存储节点1和节点之间的路径长度
int len[N];//记录到达节点i经历的路径长度
bool vis[N];//记录节点是否被访问
int n,m;

void bfs(){
	int t=q.front();//取队列的第一个元素 
	q.pop();//删除队列的第一个元素 
	//防止第一个节点为1 
	if(t==n){
		return;
	}	
	//列举每一个节点所连接的节点 
	for(int i=0;i<g[t].size();i++){
		if(!vis[g[t][i]]){
			q.push(g[t][i]);//若没用被访问过入队列 
			vis[g[t][i]]=1;//做标记 
			len[g[t][i]]=len[t]+1;//路径加1
			//若访问到最后一个节点则返回 
			if(g[t][i]==n){
				return;
			}
		}
	}
	bfs();
}

signed main(){
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=0;i<m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		g[u].push_back(v);
		g[v].push_back(u);
		//若遇到节点1则使用数组num来记录节点与1之间的路径长度 
		if(u==1){
			num[v]=w;
		}  
		if(v==1){
			num[u]=w;
		}
	}
	q.push(1);
	vis[1]=1;
	bfs();
	if(len[n]==m){
		cout<<len[n]-1+num[g[1][0]];//若路径长度恰好等于节点数则第一条路不能变为1 
	}else{
		cout<<len[n];
	}
	
	return 0;
} 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

古谷彻

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

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

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

打赏作者

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

抵扣说明:

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

余额充值