2.7C语言学习

P1111 修复公路

一道运用并查集来写的题,对每次操作用并查集处理,同时进行是否是一个共同祖先的判断,每次合并两个节点,显然如果原先不连通那么合并之后联通块数量--,操作一次就对n减一次,如果n等于1了说明修复成功

#include<bits/stdc++.h>
using namespace std;
int father[10009];
int flag[10009]={1};
struct node{
	int a,b,time;
};
node c[100009];
bool cmp(node a,node b){
	return a.time<b.time;
}
int find(int k){
	if(father[k]==k)return k;
	return father[k]=find(father[k]);
}
int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++){
		scanf("%d %d %d",&c[i].a,&c[i].b,&c[i].time);
	}
	for(int i=1;i<=n;i++){
		father[i]=i;
	}
	sort(c+1,c+1+m,cmp);
	for(int i=1;i<=m;i++){
		int fx=find(c[i].a),fy=find(c[i].b);
		if(fx!=fy){
			father[fx]=fy;
			n--;
		}
		if(n==1){
			printf("%d",c[i].time);
			return 0;
		}
	}
	printf("-1");
	return 0;
}

P2759 奇怪的函数

x的位数=log10(x)+1;【取整】

log10(double)是cmath头文件里自带的10为底的对数

可是题目的数很大呐。

利用对数运算,可以把指数提出来,作为系数

即log(x^x)=x*log(x)

直接枚举x?试试看输入2000000000,发现过了10s才出答案两亿多

说明答案是整型范围内的,但时间效率却是O(200000000)太大了

考虑到10为底的对数函数是单调递增的,所以可以用二分答案

比起题解各种各样的方法,这个可以说是最易懂的

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
	ll n;
	ll left=1,right=2e9;
	scanf("%lld",&n);
	while(left<right){
		ll mid=(left+right)/2;
		ll len=(ll)(mid*log10(1.0*mid))+1;
		if(len<n)left=mid+1;
		else right=mid;
	}
	printf("%lld",left);
	return 0;
}

P8800 [蓝桥杯 2022 国 B] 卡牌

由于这题是让我们求最大,所以要么用贪心做,要么用二分答案做。

显然,在这题中,如果我们无法凑出 x 套牌,那么一定也无法凑出 x+1 套牌。

所以,这题是可以用二分答案的。

由于我们二分的是牌数,所以我们可以写出下面的 check 函数

bool check(ll x){
	ll cnt=0;
	for(int i=1;i<=n;i++){
		if(x-a[i]<=b[i])cnt+=max(x-a[i],(long long)0);
			else return false;
	}
	if(cnt<=m)return true;
	return false;
}

由于题目说要每种花色都有,所以如果 x−ai​≤bi​ 时我们就可以累加需要手写的牌数了,最后在判断一下sum 是否≤m 即可。

接着我们思考一个问题,为什么只有 x−ai​≤bi​ 时才累加sum 呢?

我们先将柿子变形一下,得到x≤ai​+bi​。

由于 x 表示的是要凑出 x 套牌,那么显然只有原有的牌数 ai​ ,加上能够手写的牌数 bi​ 是小于 x 的时候才能进行累加手写牌的数量的。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[200009],b[200009];
ll ans,n,m;
bool check(ll x){
	ll cnt=0;
	for(int i=1;i<=n;i++){
		if(x-a[i]<=b[i])cnt+=max(x-a[i],(long long)0);
			else return false;
	}
	if(cnt<=m)return true;
	return false;
}
int main(){
	scanf("%lld %lld",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=n;i++){
		scanf("%lld",&b[i]);
	}
	ll left=0,right=1e17;
	while(left<=right){
		ll mid=(left+right)/2;
		if(check(mid)){
			ans=mid;
			left=mid+1;
		}
		else{
			right=mid-1;
		}
	}
	printf("%lld",ans);
	return 0;
}

P1874 快速求和

这题自己是搞不定了,看看他们的优质做法吧

#include<bits/stdc++.h>
#define int unsigned long long
using namespace std;

string str;
int s,n,tot;
int a[100031];
int num[55][55];
int dp[55][100031];
bool z;

signed main(){
    srand(time(0));
	cin>>str>>s;
	n=str.size();
	for(int i=0;str[i];i++){
		if(str[i]!='0') z=1;
		if(z) a[++tot]=str[i]-'0';
	}
	for(int i=1;i<=tot;i++){
		num[i][i]=a[i];
		for(int j=i;j-i<=11&&j<=tot;j++)
			num[i][j]=num[i][j-1]*10+a[j];
	}
	for(int i=0;i<=tot+1;i++)
	    for(int j=0;j<=s+1;j++)
	        dp[i][j]=0x7fffffff;
	dp[0][0]=0;
	for(int i=1;i<=tot;i++)
		for(int k=1;k<=11;k++)
			if(i>=k)
				for(int j=num[i-k+1][i];j<=s;j++)
					dp[i][j]=min(dp[i][j],dp[i-k][j-num[i-k+1][i]]+1);
	if(dp[tot][s]>tot) cout<<-1;
	else cout<<dp[tot][s]-1;
	return 0;
}


一、栈的基本概念
1、栈的定义
栈(Stack):是只允许在一端进行插入或删除的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。

栈顶(Top):线性表允许进行插入删除的那一端。
栈底(Bottom):固定的,不允许进行插入和删除的另一端。
空栈:不含任何元素的空表。

栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构

2、栈的常见基本操作
InitStack(&S):初始化一个空栈S。
StackEmpty(S):判断一个栈是否为空,若栈为空则返回true,否则返回false。
Push(&S, x):进栈(栈的插入操作),若栈S未满,则将x加入使之成为新栈顶。
Pop(&S, &x):出栈(栈的删除操作),若栈S非空,则弹出栈顶元素,并用x返回。
GetTop(S, &x):读栈顶元素,若栈S非空,则用x返回栈顶元素。

#include<bits/stdc++.h>
using namespace std;
int a[100009];
int bot=0,top=0;
void push(){
	scanf("%d",&a[top]);
	top++;
}
void pop(){
	if(top==bot){
		printf("栈已空\n");
		return; 
	}
	top--;
}
void empty(){
	if(top==bot){
		printf("空栈\n");
	}
	else printf("非空");
}
int main(){
	return 0;
}

  • 22
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值