2.19学习总结

1.中位数

2.统计和

3.铺设道路

4.岛屿个数

5.冶炼金属

6.飞机降落

7.接龙数列

中位数https://www.luogu.com.cn/problem/P1168

题目描述

给定一个长度为 �N 的非负整数序列 �A,对于前奇数项求中位数。

输入格式

第一行一个正整数 �N。

第二行 �N 个正整数 �1...�A1...N​。

输出格式

共 ⌊�+12⌋⌊2N+1​⌋ 行,第 �i 行为 �1...2�−1A1...2i−1​ 的中位数。

输入输出样例

输入 #1复制

7

1 3 5 7 9 11 6

输出 #1复制

1

3

5

6

输入 #2复制

7

3 1 5 9 8 7 6

输出 #2复制

3

3

5

6

说明/提示

对于 20%20% 的数据,�≤100N≤100;

对于 40%40% 的数据,�≤3000N≤3000;

对于 100%100% 的数据,1≤�≤1000001≤N≤100000,0≤��≤1090≤Ai​≤109。

思路:运用保证大根堆中的最大数小于小根堆中的最小数,也就是大根堆的队首小于小根堆的队首,然后比较两个堆的长度,较长的一个取出队首元素

下面是很形象的对顶堆:上面是倒着的大根堆,下面是正的小根堆

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f

//保证大跟堆的最大的数都小于小根堆最小的数,即大根堆的队首小于小根堆的队首 

priority_queue<int>q1;
priority_queue<int,vector<int>,greater<int> >q2;

signed main(){
	int n;
	cin>>n;
	for (int i=1;i<=n;++i){
		int a;
		cin>>a;
		if (q1.empty()){
			q1.push(a);
			cout<<q1.top()<<endl;
			continue;
		}
		if (a>q1.top()) q2.push(a);
		else q1.push(a);
		if ((int )q2.size()-(int)q1.size()>1){
			q1.push(q2.top());
			q2.pop();
		}else if ((int)q1.size()-(int)q2.size()>1){
			q2.push(q1.top());
			q1.pop();
		}
		if (i%2==1){
			if (q1.size()>q2.size()) cout<<q1.top()<<endl;
			else if (q2.size()>q1.size()) cout<<q2.top()<<endl;
		}
	}
} 

铺设道路https://www.luogu.com.cn/problem/P5019

题目描述

春春是一名道路工程师,负责铺设一条长度为 �n 的道路。

铺设道路的主要工作是填平下陷的地表。整段道路可以看作是 �n 块首尾相连的区域,一开始,第 �i 块区域下陷的深度为 ��di​ 。

春春每天可以选择一段连续区间 [�,�][L,R] ,填充这段区间中的每块区域,让其下陷深度减少 11。在选择区间时,需要保证,区间内的每块区域在填充前下陷深度均不为 00 。

春春希望你能帮他设计一种方案,可以在最短的时间内将整段道路的下陷深度都变为 00 。

输入格式

输入文件包含两行,第一行包含一个整数 �n,表示道路的长度。 第二行包含 �n 个整数,相邻两数间用一个空格隔开,第 �i 个整数为 ��di​ 。

输出格式

输出文件仅包含一个整数,即最少需要多少天才能完成任务。

输入输出样例

输入 #1复制

6

4 3 2 5 3 5

输出 #1复制

9

说明/提示

【样例解释】

一种可行的最佳方案是,依次选择: [1,6][1,6]、[1,6][1,6]、[1,2][1,2]、[1,1][1,1]、[4,6][4,6]、[4,4][4,4]、[4,4][4,4]、[6,6][6,6]、[6,6][6,6]。

【数据规模与约定】

对于 30%30% 的数据,1≤�≤101≤n≤10 ;

对于 70%70% 的数据,1≤�≤10001≤n≤1000 ;

对于 100%100% 的数据,1≤�≤100000,0≤��≤100001≤n≤100000,0≤di​≤10000 。

用贪心做

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f

const int N=1e5+5;

int a[N];

signed main(){
	int n;
	cin>>n;
	for (int i=1;i<=n;++i){
		cin>>a[i];
	}
	int sum=0;
	for (int i=2;i<=n;++i){
		if (a[i]>a[i-1])sum+=a[i]-a[i-1];
	}
	cout<<sum+a[1];
}

统计和https://www.luogu.com.cn/problem/P2068

题目描述

给定一个长度为 �(�≤100000)n(n≤100000),初始值都为 00 的序列,�(�≤100000)x(x≤100000) 次的修改某些位置上的数字,每次加上一个数,然后提出 �(�≤100000)y(y≤100000) 个问题,求每段区间的和。

输入格式

第一行 11 个整数,表示序列的长度 �n。

第二行 11 个整数,表示操作的次数 �w。

后面依次是 �w 行,分别表示加入和询问操作。

其中,加入用 x 表示,询问用 y 表示。

�x的格式为 x a b 表示在序列上第 �a 个数加上 �b。保证 1≤�≤�1≤a≤n,1≤�≤1091≤b≤109。

�y 的格式为 y a b 表示询问 �a 到 �b 区间的加和。保证 1≤�≤�≤�1≤a≤b≤n。

输出格式

每行一个正整数,分别是每次询问的结果

输入输出样例

输入 #1复制

5

4

x 3 8

y 1 3

x 4 9

y 3 4

输出 #1复制

8

17

树状数组板子

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f

const int N=1e5+5;

int tr[N];

void update(int x,int k){
	while (x<=N){
		tr[x]+=k;
		x+=lowbit(x);
	}
}

int query(int x){
	int res=0;
	while (x>0){
		res+=tr[x];
		x-=lowbit(x);
	}
	return res;
}

signed main(){
	memset(tr,0,sizeof(tr));
	int n,w;
	cin>>n>>w;
	for (int i=0;i<w;++i){
		char op;
		cin>>op;
		if (op=='x'){
			int a,b;
			cin>>a>>b;
			update(a,b);
		}else if (op='y'){
			int a,b;
			cin>>a>>b;
			int sum=query(b)-query(a-1);
			cout<<sum<<endl;
		}
	}
}

接龙数列https://www.dotcpp.com/oj/problem3152.html

题描述
对于一个长度为K的整数数列:A 1 , A 2 , . 。。, A K,我们称接龙数列当且仅当 A i的首位数字正好等于 A i−1的末位数字 (2 ≤ i ≤ K)。

例如 12, 23, 35, 56, 61, 11 是接龙数列;12, 23, 34, 56 不是接龙数列,因为 56 的标题数字不等于 34 的末位数字。所有长度为 1 的整数数列都是接龙数列数列。

现在给定一个长度为N的数列A 1 , A 2 , 。。。, A N,请你计算最少总共删除多少个数,可以使剩余的序列是接龙序列?
输入格式
第一行包含一个整数N。

第二行包含N个整数A 1 , A 2 , 。。。,一个。
输出格式
一个整数代表答案。
样例输入

复制

sampledata 复制代码
5
11 121 22 12 2023

样例输出

复制

sampledata 复制代码
1

提示
删除 22,剩余 11, 121, 12, 2023 是接龙数列。

对于20%的数据,1 ≤ N ≤ 20。

对于50%的数据,1 ≤ N ≤ 10000。

对于100%的数据,1 ≤ N ≤ 10 5,1 ≤ A i ≤ 10 9。所有A i保证不包含前导0。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
 
const int N=1e5+5;
 
int dp[N],n;
 
signed main(){
    cin>>n;
    int maxn=0;
    for (int i=1;i<=n;++i){
        string s;
        cin>>s;
        int first=s[0]-'0',second=s[s.size()-1]-'0';
        dp[second]=max(dp[second],dp[first]+1);
        maxn=max(maxn,dp[second]);
    }
    cout<<n-maxn;
}

岛屿个数https://www.dotcpp.com/oj/problem3153.html

题目描述

小蓝得到了一副大小为 M × N 的格子地图,可以将其视作一个只包含字符'0'(代表海水)和 '1'(代表陆地)的二维数组,地图之外可以视作全部是海水,每个岛屿由在上/下/左/右四个方向上相邻的 '1' 相连接而形成。

在岛屿 A 所占据的格子中,如果可以从中选出 k 个不同的格子,使得他们的坐标能够组成一个这样的排列:(x0, y0),(x1, y1), . . . ,(xk−1, yk−1),其中(x(i+1)%k , y(i+1)%k) 是由 (xi , yi) 通过上/下/左/右移动一次得来的 (0 ≤ i ≤ k − 1),

此时这 k 个格子就构成了一个 "环"。如果另一个岛屿 B 所占据的格子全部位于这个 "环" 内部,此时我们将岛屿 B 视作是岛屿 A 的子岛屿。若 B 是 A 的子岛屿,C 又是 B 的子岛屿,那 C 也是 A 的子岛屿。

请问这个地图上共有多少个岛屿?在进行统计时不需要统计子岛屿的数目。

输入格式

第一行一个整数 T,表示有 T 组测试数据。

接下来输入 T 组数据。对于每组数据,第一行包含两个用空格分隔的整数M、N 表示地图大小;接下来输入 M 行,每行包含 N 个字符,字符只可能是'0' 或 '1'。

输出格式

对于每组数据,输出一行,包含一个整数表示答案。

样例输入

复制

2

5 5

01111

11001

10101

10001

11111

5 6

111111

100001

010101

100001

111111

样例输出

复制

1

3

提示

对于第一组数据,包含两个岛屿,下面用不同的数字进行了区分:

01111

11001

10201

10001

11111

岛屿 2 在岛屿 1 的 "环" 内部,所以岛屿 2 是岛屿 1 的子岛屿,答案为 1。

对于第二组数据,包含三个岛屿,下面用不同的数字进行了区分:

111111

100001

020301

100001

111111

注意岛屿 3 并不是岛屿 1 或者岛屿 2 的子岛屿,因为岛屿 1 和岛屿 2 中均没有"环"。

对于 30% 的评测用例,1 ≤ M, N ≤ 10。

对于 100% 的评测用例,1 ≤ T ≤ 10,1 ≤ M, N ≤ 50。

思路:DFS+染色,主要问题点在与找环

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f

const int N=1e5+5;

int t,a[55][55];

void dfs(int x,int y){
	a[x][y]=2;
	int dir[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
	for (int i=0;i<8;++i){
		int tx=x+dir[i][0],ty=y+dir[i][1];
		if (tx<0 || ty<0 || tx>=55 ||ty>=55 ) continue;
		if (!a[tx][ty] ){
			dfs(tx,ty);
		}
	}
}

void dfs1(int x,int y){
	a[x][y]=2;
	int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
	for (int i=0;i<4;++i){
		int tx=x+dir[i][0],ty=y+dir[i][1];
		if (tx<0 || ty<0 || tx>=55 ||ty>=55 ) continue;
		if (a[tx][ty]==1){
			dfs1(tx,ty);
		}
	}
}

signed main(){
	cin>>t;
	while (t--){
		int n,m;
		cin>>n>>m;
		memset(a,0,sizeof(a));
		for (int i=1;i<=n;++i){
			for (int j=1;j<=m;++j){
				scanf("%1d",&a[i][j]);
			}
		}
		dfs(0,0);
		for (int i=1;i<=n;++i){
			for (int j=1;j<=m;++j){
				if (a[i][j]==0) a[i][j]=1;
			}
		}
		int cnt=0;
		for (int i=1;i<=n;++i){
			for (int j=1;j<=m;++j){
				if (a[i][j]==1){
					cnt++;
					dfs1(i,j);
				}
			}
		}
		cout<<cnt<<endl;
	}
}

飞机降落https://www.dotcpp.com/oj/problem3151.html

题目描述

N 架飞机准备降落到某个只有一条跑道的机场。其中第 i 架飞机在 Ti 时刻到达机场上空,到达时它的剩余油料还可以继续盘旋 Di 个单位时间,即它最早

可以于 Ti 时刻开始降落,最晚可以于 Ti + Di 时刻开始降落。降落过程需要 Li个单位时间。

一架飞机降落完毕时,另一架飞机可以立即在同一时刻开始降落,但是不能在前一架飞机完成降落前开始降落。

请你判断 N 架飞机是否可以全部安全降落。

输入格式

输入包含多组数据。

第一行包含一个整数 T,代表测试数据的组数。

对于每组数据,第一行包含一个整数 N。

以下 N 行,每行包含三个整数:Ti,Di 和 Li。

输出格式

对于每组数据,输出 YES 或者 NO,代表是否可以全部安全降落。

样例输入

复制

2

3

0 100 10

10 10 10

0 2 20

3

0 10 20

10 10 20

20 10 20

样例输出

复制

YES

NO

提示

对于第一组数据,可以安排第 3 架飞机于 0 时刻开始降落,20 时刻完成降落。安排第 2 架飞机于 20 时刻开始降落,30 时刻完成降落。安排第 1 架飞机于 30 时刻开始降落,40 时刻完成降落。

对于第二组数据,无论如何安排,都会有飞机不能及时降落。

对于 30% 的数据,N ≤ 2。

对于 100% 的数据,1 ≤ T ≤ 10,1 ≤ N ≤ 10,0 ≤ Ti , Di , Li ≤ 105。

DFS遍历所有的可能

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
 
const int N=1e4+5;
 
struct node{
    int t,d,l;
}a[15];
 
int T,n,vis[15];
 
bool dfs(int x,int end){
    if (x>n) return true;
    for (int i=1;i<=n;++i){
        if (!vis[i]){
            vis[i]=1;
            if (end<a[i].t){
                if (dfs(x+1,a[i].t+a[i].l)) return true;
            }
            else if (end<=a[i].d+a[i].t){
                if (dfs(x+1,end+a[i].l)) return true;
            }
            vis[i]=0;
        }
    }
    return false;
}
 
signed main(){
    cin>>T;
    while (T--){
        memset(vis,0,sizeof(vis));
        cin>>n;
        for (int i=1;i<=n;++i){
        cin>>a[i].t>>a[i].d>>a[i].l;
        }
        if (dfs(1,0)) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

冶炼金属https://www.dotcpp.com/oj/problem3150.html

题目描述

小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V,V 是一个正整数,这意味着消耗 V 个普通金

属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V 时,无法继续冶炼。

现在给出了 N 条冶炼记录,每条记录中包含两个整数 A 和 B,这表示本次投入了 A 个普通金属 O,最终冶炼出了 B 个特殊金属 X。每条记录都是独立

的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。

根据这 N 条冶炼记录,请你推测出转换率 V 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。

输入格式

第一行一个整数 N,表示冶炼记录的数目。

接下来输入 N 行,每行两个整数 A、B,含义如题目所述。

输出格式

输出两个整数,分别表示 V 可能的最小值和最大值,中间用空格分开。

样例输入

复制

3

75 3

53 2

59 2

样例输出

复制

20 25

提示

当 V = 20 时,有:⌊75/20⌋ = 3,⌊ 53/20 ⌋ = 2,⌊ 59/20 ⌋ = 2,可以看到符合所有冶炼记录。

当 V = 25 时,有:⌊75/25⌋ = 3,⌊ 53/25 ⌋ = 2,⌊ 59/25 ⌋ = 2,可以看到符合所有冶炼记录。

且再也找不到比 20 更小或者比 25 更大的符合条件的 V 值了。

对于 30% 的评测用例,1 ≤ N ≤ 102。

对于 60% 的评测用例,1 ≤ N ≤ 103。

对于 100% 的评测用例,1 ≤ N ≤ 104,1 ≤ B ≤ A ≤ 109。

直接遍历所有的情况

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
 
const int N=1e4+5;
 
int l,r,n,a[N],b[N],maxn,minn=INF;
 
signed main(){
    cin>>n;
    for (int i=1;i<=n;++i){
        cin>>a[i]>>b[i];
        maxn=max(maxn,a[i]);
        minn=min(minn,a[i]);
    }
    for (int j=1;j<=maxn;++j){
        for (int i=1;i<=n;++i){
            if (a[i]/j!=b[i]) break;
            if (i==n && !l) l=j;
            if (i==n ) r=j; 
        }
    }
    cout<<l<<" "<<r;
}
相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码4 天前
嵌入式学习路线
学习
毛小茛4 天前
计算机系统概论——校验码
学习
babe小鑫4 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms4 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下4 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。4 天前
2026.2.25监控学习
学习
im_AMBER4 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J4 天前
从“Hello World“ 开始 C++
c语言·c++·学习