[蓝桥杯 2023 省 B] 冶炼金属
题目描述
小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V V V, V V V 是一个正整数,这意味着消耗 V V V 个普通金属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V V V 时,无法继续冶炼。
现在给出了 N N N 条冶炼记录,每条记录中包含两个整数 A A A 和 B B B,这表示本次投入了 A A A 个普通金属 O,最终冶炼出了 B B B 个特殊金属 X。每条记录都是独立的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。
根据这 N N N 条冶炼记录,请你推测出转换率 V V V 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。
输入格式
第一行一个整数 N N N,表示冶炼记录的数目。
接下来输入 N N N 行,每行两个整数 A , B A,B A,B,含义如题目所述。
输出格式
输出两个整数,分别表示 V V V 可能的最小值和最大值,中间用空格分开。
样例 #1
样例输入 #1
3
75 3
53 2
59 2
样例输出 #1
20 25
提示
【样例说明】
当 V = 20 V=20 V=20 时,有: ⌊ 75 20 ⌋ = 3 , ⌊ 53 20 ⌋ = 2 , ⌊ 59 20 ⌋ = 2 \left\lfloor\frac{75}{20}\right\rfloor=3,\left\lfloor\frac{53}{20}\right\rfloor=2,\left\lfloor\frac{59}{20}\right\rfloor=2 ⌊2075⌋=3,⌊2053⌋=2,⌊2059⌋=2,可以看到符合所有冶炼记录。
当 V = 25 V=25 V=25 时,有: ⌊ 75 25 ⌋ = 3 , ⌊ 53 25 ⌋ = 2 , ⌊ 59 25 ⌋ = 2 \left\lfloor\frac{75}{25}\right\rfloor=3,\left\lfloor\frac{53}{25}\right\rfloor=2,\left\lfloor\frac{59}{25}\right\rfloor=2 ⌊2575⌋=3,⌊2553⌋=2,⌊2559⌋=2,可以看到符合所有冶炼记录。
且再也找不到比 20 20 20 更小或者比 25 25 25 更大的符合条件的 V V V 值了。
【评测用例规模与约定】
对于 30 % 30 \% 30% 的评测用例, 1 ≤ N ≤ 1 0 2 1 \leq N \leq 10^{2} 1≤N≤102。
对于 60 % 60 \% 60% 的评测用例, 1 ≤ N ≤ 1 0 3 1 \leq N \leq 10^{3} 1≤N≤103。
对于 100 % 100 \% 100% 的评测用例, 1 ≤ N ≤ 1 0 4 1 \leq N \leq 10^{4} 1≤N≤104, 1 ≤ B ≤ A ≤ 1 0 9 1 \leq B \leq A \leq 10^{9} 1≤B≤A≤109。
蓝桥杯 2023 省赛 B 组 C 题。
思路:对于每一组(a,b),都有使条件成立的最大值和最小值,求交集, 即求最大值的最小值,求最小值的最大值,数学题
AC Code
#include <bits/stdc++.h>
#include <vector>
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// set<int>::iterator it;
int n;
int a;
int b;
signed main(void)
{
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n;
int ans1=INF,ans2=-1;
f(i,0,n-1)
{
cin >> a>> b;
ans1=min(ans1,a / b);
ans2=max(ans2,a/(b+1)+1);//考虑造b+1,此时a/(b+1)刚好不满足条件,所以加一,就是最小值
}
cout << ans2 << " " << ans1 << endl;
return 0;
}
[蓝桥杯 2023 省 B] 飞机降落
题目描述
N N N 架飞机准备降落到某个只有一条跑道的机场。其中第 i i i 架飞机在 T i T_{i} Ti 时刻到达机场上空,到达时它的剩余油料还可以继续盘旋 D i D_{i} Di 个单位时间,即它最早可以于 T i T_{i} Ti 时刻开始降落,最晩可以于 T i + D i T_{i}+D_{i} Ti+Di 时刻开始降落。降落过程需要 L i L_{i} Li 个单位时间。
一架飞机降落完毕时,另一架飞机可以立即在同一时刻开始降落,但是不能在前一架飞机完成降落前开始降落。
请你判断 N N N 架飞机是否可以全部安全降落。
输入格式
输入包含多组数据。
第一行包含一个整数 T T T,代表测试数据的组数。
对于每组数据,第一行包含一个整数 N N N。
以下 N N N 行,每行包含三个整数 T i , D i , L i T_{i},D_{i},L_{i} Ti,Di,Li。
输出格式
对于每组数据,输出 YES
或者 NO
,代表是否可以全部安全降落。
样例 #1
样例输入 #1
2
3
0 100 10
10 10 10
0 2 20
3
0 10 20
10 10 20
20 10 20
样例输出 #1
YES
NO
提示
【样例说明】
对于第一组数据,可以安排第 3 架飞机于 0 时刻开始降落,20 时刻完成降落。安排第 2 架飞机于 20 时刻开始降落,30 时刻完成降落。安排第 1 架飞机于 30 时刻开始降落,40 时刻完成降落。
对于第二组数据,无论如何安排,都会有飞机不能及时降落。
【评测用例规模与约定】
对于 30 % 30 \% 30% 的数据, N ≤ 2 N \leq 2 N≤2。
对于 100 % 100 \% 100% 的数据, 1 ≤ T ≤ 10 1 \leq T \leq 10 1≤T≤10, 1 ≤ N ≤ 10 1 \leq N \leq 10 1≤N≤10, 0 ≤ T i , D i , L i ≤ 1 0 5 0 \leq T_{i},D_{i},L_{i} \leq 10^{5} 0≤Ti,Di,Li≤105。
蓝桥杯 2023 省赛 B 组 D 题。
思路:DFS,直接暴搜,dp尼姆,沙沟才dp
AC Code
#include <bits/stdc++.h>
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// set<int>::iterator it;
int n;
int flag = 0;
struct temp
{
int l, r, t; // 最早降落,最迟降落,降落时间
};
struct temp a[maxn];
bool vis[maxn] = {false};
void dfs(int ti, int cnt) // 现在的时间,降落的飞机数量
{
if (cnt == n)
{
flag = 1;
return;
}
f(i, 1, n)
{
if (!vis[i] && a[i].r >= ti)
{
vis[i] = true;
if (a[i].l >= ti) // 最早降落时间大于等于现在时间
{
dfs(a[i].l + a[i].t, cnt + 1);
}
else
{
dfs(ti + a[i].t, cnt + 1);
}
vis[i] = false;
}
}
return;
}
void solve()
{
flag = 0;
cin >> n;
f(i, 1, n)
{
cin >> a[i].l >> a[i].r >> a[i].t;
a[i].r += a[i].l;
}
dfs(0,0);
if (flag == 0)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
}
return;
}
signed main(void)
{
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
[蓝桥杯 2023 省 B] 接龙数列
题目描述
对于一个长度为 K K K 的整数数列: A 1 , A 2 , … , A K A_{1},A_{2},\ldots,A_{K} A1,A2,…,AK,我们称之为接龙数列当且仅当 A i A_{i} Ai 的首位数字恰好等于 A i − 1 A_{i-1} Ai−1 的末位数字( 2 ≤ i ≤ K 2 \leq i \leq K 2≤i≤K)。
例如 12 , 23 , 35 , 56 , 61 , 11 12,23,35,56,61,11 12,23,35,56,61,11 是接龙数列; 12 , 23 , 34 , 56 12,23,34,56 12,23,34,56 不是接龙数列,因为 56 56 56 的首位数字不等于 34 34 34 的末位数字。所有长度为 1 1 1 的整数数列都是接龙数列。
现在给定一个长度为 N N N 的数列 A 1 , A 2 , … , A N A_{1},A_{2},\ldots,A_{N} A1,A2,…,AN,请你计算最少从中删除多少 个数,可以使剩下的序列是接龙序列?
输入格式
第一行包含一个整数 N N N。
第二行包含 N N N 个整数 A 1 , A 2 , … , A N A_{1},A_{2},\ldots,A_{N} A1,A2,…,AN。
输出格式
一个整数代表答案。
样例 #1
样例输入 #1
5
11 121 22 12 2023
样例输出 #1
1
提示
【样例说明】
删除 22 22 22,剩余 11 , 121 , 12 , 2023 11,121,12,2023 11,121,12,2023 是接龙数列。
【评测用例规模与约定】
对于 20 % 20 \% 20% 的数据, 1 ≤ N ≤ 20 1 \leq N \leq 20 1≤N≤20。
对于 50 % 50 \% 50% 的数据, 1 ≤ N ≤ 1 0 4 1 \leq N \leq 10^4 1≤N≤104。
对于 100 % 100 \% 100% 的数据, 1 ≤ N ≤ 1 0 5 1 \leq N \leq 10^{5} 1≤N≤105, 1 ≤ A i ≤ 1 0 9 1 \leq A_{i} \leq 10^{9} 1≤Ai≤109。所有 A i A_{i} Ai 保证不包含前导 0。
蓝桥杯 2023 省赛 B 组 E 题。
思路:线性dp,状态有点难想,不过只要设计出了状态,转移方程很好想
AC Code
#include <algorithm>
#include <bits/stdc++.h>
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// dp[i]代表以i结尾的最长接龙序列
int n;
string s[maxn];
int dp[20] = {0};
void solve()
{
cin >> n;
f(i, 1, n)
{
cin >> s[i];
}
f(i, 1, n)
{
dp[s[i][s[i].size() - 1] - '0'] = max(dp[s[i][s[i].size() - 1] - '0'], dp[s[i][0] - '0'] + 1);
}
cout << n - dp[max_element(dp, dp + 9) - dp] << endl;
}
signed main(void)
{
ios::sync_with_stdio(false), cin.tie(nullptr);
int t = 1;
while (t--)
{
solve();
}
return 0;
}
[蓝桥杯 2023 省 A] 更小的数
题目描述
小蓝有一个长度均为 n n n 且仅由数字字符 0 ∼ 9 0 \sim 9 0∼9 组成的字符串,下标从 0 0 0 到 n − 1 n-1 n−1,你可以将其视作是一个具有 n n n 位的十进制数字 n u m num num,小蓝可以从 n u m num num 中选出一段连续的子串并将子串进行反转,最多反转一次。小蓝想要将选出的子串进行反转后再放入原位置处得到的新的数字 n u m n e w num_{new} numnew 满足条件 n u m n e w < n u m num_{new}<num numnew<num,请你帮他计算下一共有多少种不同的子串选择方案,只要两个子串在 n u m num num 中的位置不完全相同我们就视作是不同的方案。
注意,我们允许前导零的存在,即数字的最高位可以是 0 0 0,这是合法的。
输入格式
输入一行包含一个长度为 n n n 的字符串表示 n u m num num(仅包含数字字符 0 ∼ 9 0 \sim 9 0∼9),从左至右下标依次为 0 ∼ n − 1 0 \sim n-1 0∼n−1。
输出格式
输出一行包含一个整数表示答案。
样例 #1
样例输入 #1
210102
样例输出 #1
8
提示
【样例说明】
一共有 8 8 8 种不同的方案:
- 所选择的子串下标为 0 ∼ 1 0\sim1 0∼1,反转后的 n u m n e w = 120102 < 210102 num_{new} = 120102 < 210102 numnew=120102<210102;
- 所选择的子串下标为 0 ∼ 2 0\sim2 0∼2,反转后的 n u m n e w = 012102 < 210102 num_{new} = 012102 < 210102 numnew=012102<210102;
- 所选择的子串下标为 0 ∼ 3 0\sim3 0∼3,反转后的 n u m n e w = 101202 < 210102 num_{new} = 101202 < 210102 numnew=101202<210102;
- 所选择的子串下标为 0 ∼ 4 0\sim4 0∼4,反转后的 n u m n e w = 010122 < 210102 num_{new} = 010122 < 210102 numnew=010122<210102;
- 所选择的子串下标为 0 ∼ 5 0\sim5 0∼5,反转后的 n u m n e w = 201012 < 210102 num_{new} = 201012 < 210102 numnew=201012<210102;
- 所选择的子串下标为 1 ∼ 2 1\sim2 1∼2,反转后的 n u m n e w = 201102 < 210102 num_{new} = 201102 < 210102 numnew=201102<210102;
- 所选择的子串下标为 1 ∼ 4 1\sim4 1∼4,反转后的 n u m n e w = 201012 < 210102 num_{new} = 201012 < 210102 numnew=201012<210102;
- 所选择的子串下标为 3 ∼ 4 3\sim4 3∼4,反转后的 n u m n e w = 210012 < 210102 num_{new} = 210012 < 210102 numnew=210012<210102。
【评测用例规模与约定】
对于 20 % 20\% 20% 的评测用例, 1 ≤ n ≤ 100 1 \le n \le 100 1≤n≤100;
对于 40 % 40\% 40% 的评测用例, 1 ≤ n ≤ 1000 1 \le n \le 1000 1≤n≤1000;
对于所有评测用例, 1 ≤ n ≤ 5000 1 \le n \le 5000 1≤n≤5000。
思路:区间DP,没学过,被狠狠薄纱了,状态转移方程是 dp[i][j] = dp[i + 1][j - 1]。这意味着要计算 dp[i][j],我们需要知道 dp[i + 1][j - 1] 的值,这就决定了我们需要从后向前遍历字符串。确保了我们在计算一个状态时,所依赖的状态已经被计算过了。
AC Code
#include <bits/stdc++.h>
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// set<int>::iterator it;
string s;
int dp[5050][5050];
signed main(void)
{
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> s;
int n = s.size();
f(i, 0, n - 1)
{
if (s[i] > s[i + 1])
{
dp[i][i + 1] = 1;//区间DP,要给最小的区间初始化
}
}
int ans = 0;
ff(i, n-1, 0)
{
f(j, i, n - 1)// 找i后面的
{
if (s[i] > s[j])
{
dp[i][j] = 1;//可以就是1
}
else if (s[i] == s[j])
{
dp[i][j] = dp[i + 1][j - 1];//相等的话就看里面的,状态转移方程
}
if (dp[i][j] == 1)
{
ans++;
}
}
}
cout << ans << endl;
return 0;
}