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 , 。。。,一个。
输出格式
一个整数代表答案。
样例输入复制
sampledata5 11 121 22 12 2023
样例输出
复制
sampledata1
提示
删除 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;
}