蓝桥杯14届B组题解C++(1)
冶炼金属
题目描述
小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V,V 是一个正整数,这意味着消耗 V 个普通金
属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V 时,无法继续冶炼。
现在给出了 N 条冶炼记录,每条记录中包含两个整数 A 和 B,这表示本次投入了 A 个普通金属 O,最终冶炼出了 B 个特殊金属 X。每条记录都是独立
的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。
根据这 N 条冶炼记录,请你推测出转换率 V 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。
输入格式
第一行一个整数 N,表示冶炼记录的数目。
接下来输入 N 行,每行两个整数 A、B,含义如题目所述。
输出格式
输出两个整数,分别表示 V 可能的最小值和最大值,中间用空格分开。
解题思路
可以将题目用公式化表达如下含义
如果是75 3,
那么满足它的
V
的最大值是
25
,最小值就是
⌊
75
4
⌋
+
1
=
19
那么满足它的V的最大值是25,最小值就是\lfloor \frac{75}{4} \rfloor+1 = 19
那么满足它的V的最大值是25,最小值就是⌊475⌋+1=19
那么我们就是希望把所有Vi公共范围找到,并得到它的最小值和最大值
由此可推导出
V
i
的范围:
V
i
l
e
f
t
=
⌊
A
i
B
i
+
1
+
1
⌋
<
=
V
i
<
=
⌊
A
i
B
i
⌋
=
V
i
r
i
g
h
t
由此可推导出 V_i的范围: V_{i_{left}}=\lfloor\frac{A_i}{B_i+1}+1\rfloor <=V_i<= \lfloor \frac{A_i}{B_i} \rfloor=V_{i_{right}}
由此可推导出Vi的范围:Vileft=⌊Bi+1Ai+1⌋<=Vi<=⌊BiAi⌋=Viright
找到所有 V i l e f t 中最大的,找到所有 V i r i g h t 中最小的,即可求解 找到所有V_{i_{left}}中最大的,找到所有V_{i_{right}}中最小的,即可求解 找到所有Vileft中最大的,找到所有Viright中最小的,即可求解
#include <bits/stdc++.h>
using namespace std;
int main()
{
int N;
int cmin=0xffffff-1,cmax=-1;
cin>>N;
while(N--)
{
int a,b;
cin>>a>>b;
cmax = max(a/(b+1)+1,cmax);
cmin = min(a/b,cmin);
}
cout<<cmax<<" " <<cmin;
}
飞机降落
题目描述
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 ≤ 10^5。
思路
采用深度优先搜索做题即可。
#include <bits/stdc++.h>
using namespace std;
int N;
typedef struct node{
int t,d,l;
}Node;
bool find_;
void dfs(int n,int tim,vector<Node>& a,vector<bool>& vis)
{
find_=false;
if(find_)return;
if(n==N)
{
find_ = true;
}
for(int i=0;i<N;i++)
{
if(!vis[i]&&tim<=a[i].t+a[i].d)
{
vis[i]=1;
//保证将当前时间调整为可以降落飞机的最早时间。
dfs(n+1,max(tim,a[i].t)+a[i].l,a,vis);
if(find_) return;
vis[i]=0;
}
}
}
void solve(){
cin>>N;
vector<Node> a(N);
vector<bool> vis(N);
for(int i=0;i<N;i++)
{
cin>>a[i].t>>a[i].d>>a[i].l;
}
dfs(0,0,a,vis);
if(find_)cout<<"YES\n";
else cout<<"NO\n";
}
int main()
{
int T;
ios::sync_with_stdio(false);
cin.tie(0) ;
cout.tie(0);
cin>>T;
while(T--)
{
solve();
}
}
接龙数列
题目描述
对于一个长度为 K 的整数数列:A1, A2, . . . , AK,我们称之为接龙数列当且仅当 Ai 的首位数字恰好等于 Ai−1 的末位数字 (2 ≤ i ≤ K)。
例如 12, 23, 35, 56, 61, 11 是接龙数列;12, 23, 34, 56 不是接龙数列,因为 56的首位数字不等于 34 的末位数字。所有长度为 1 的整数数列都是接龙数列。
现在给定一个长度为 N 的数列 A1, A2, . . . , AN,请你计算最少从中删除多少个数,可以使剩下的序列是接龙序列?
输入格式
第一行包含一个整数 N。
第二行包含 N 个整数 A1, A2, . . . , AN。
输出格式
一个整数代表答案。
样例输入
5
11 121 22 12 2023
样例输出
1
提示
删除 22,剩余 11, 121, 12, 2023 是接龙数列。
对于 20% 的数据,1 ≤ N ≤ 20。
对于 50% 的数据,1 ≤ N ≤ 10000。
对于 100% 的数据,1 ≤ N ≤ 105,1 ≤ Ai ≤ 109。所有 Ai 保证不包含前导 0。
思路
题目意思可以理解为,从序列中找最长的接龙序列。
考虑动态规划。思路就是按顺序到了第n个数时,考虑以当前末位结尾的数的最大长度,或者拼接它的开头的数+1的最大长度
设置数的首位为
S
i
,
数的末尾为
E
i
状态转移方程就为
:
d
p
[
E
i
]
=
m
a
x
(
d
p
[
E
i
]
,
d
p
[
S
i
]
+
1
)
设置数的首位为S_i,数的末尾为E_i\\ 状态转移方程就为: dp[E_i] = max(dp[E_i],dp[S_i]+1)
设置数的首位为Si,数的末尾为Ei状态转移方程就为:dp[Ei]=max(dp[Ei],dp[Si]+1)
#include<bits/stdc++.h>
using namespace std;
int dp[10];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
string s;
cin>>s;
int x=s[0]-'0';
int y=s[s.size()-1]-'0';
dp[y] = max(dp[y],dp[x]+1);
}
int max_=0;
for(int i=0;i<10;i++)
max_ = max(dp[i],max_);
cout<<n-max_;
}