www.CodeFun2000.com(http://101.43.147.120/)
最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
CSDN的第一篇博客.然后比赛的时候发挥的不是很好,前15分钟切完三题就被D题关住了。赛后补题发现其实D,E都算不上什么难题。没办法,只能是自己知识面太窄了.多积累吧
1.速算机器人
2.早餐组合
3.秋叶收藏集
4.快速公交
5.追逐游戏
语法题
题意:
给你两个数组a,b以及一个数T。让你从a中选出一个数X,b中选出一个数Y,使得 X + Y ≤ T X + Y \leq T X+Y≤T. 让你求方案数. ( a , b 数组长度 ≤ 1 e 5 ) (a,b数组长度\leq1e5) (a,b数组长度≤1e5)
思路:
对a,b排序后枚举a数组的X. 由等式得到 Y ≤ T − X Y \leq T -X Y≤T−X. 二分b数组计数即可.
复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
#define ll long long
class Solution {
public:
int breakfastNumber(vector<int>& a, vector<int>& b, int x) {
sort(a.begin() , a.end());
sort(b.begin() , b.end());
ll mod = 1e9 + 7 , ans = 0;
for (auto g : a){
if (g >= x) break;
ll pos = upper_bound(b.begin(),b.end() , x - g) - b.begin();
ans = (ans + pos) % mod;
}
return ans;
}
};
题意:
给你只含R,B的字符串S。你一次可以将R修改成B,也可以将B修改成R。问最小修改代价使得字符串S形如: { R . . . R B . . . B R . . . R } . \{R...RB...BR...R\}. {R...RB...BR...R}.
即将字符串分成三段,第一三段全为R,第二段全为B。注意到每一段长度至少为1. ( ∣ S ∣ ≤ 1 e 5 ) (|S| \leq 1e5) (∣S∣≤1e5)
思路:
经典动态规划题 . 有一个技巧在于将状态分解成三段。 经典动态规划题.有一个技巧在于将状态分解成三段。 经典动态规划题.有一个技巧在于将状态分解成三段。
即状态1为: 字符串形如: { R . . . R } \ \ \{R...R\} {R...R}
状态2为: 字符串形如: { R . . . R B . . . B } \ \ \ \ \{R...RB...B\} {R...RB...B}
状态3为: 字符串形如: { R . . . R B . . . B R . . . R } \ \ \ \ \ \{R...RB...BR...R\} {R...RB...BR...R}
我们可以发现,这三个状态有很强的相关性。即状态2一定是由状态1得到.状态3一定是由1 得到 2 再 得到 3.
所以令 d p ( i , 0 / 1 / 2 ) dp(i,0/1/2) dp(i,0/1/2)代表前i个字符中,将i变成状态 0 / 1 / 2 0/1/2 0/1/2的最小代价.考虑 d p ( i ) dp(i) dp(i)与 d p ( i − 1 ) dp(i - 1) dp(i−1)之间的3个状态的转移:
d p ( i , 0 ) = d p ( i − 1 , 0 ) + S [ i ] = = B dp(i,0) = dp(i-1,0)+S[i]==B dp(i,0)=dp(i−1,0)+S[i]==B
d p ( i , 1 ) = m i n ( d p ( i − 1 , 0 ) , d p ( i − 1 , 1 ) ) + S [ i ] = = R dp(i,1) = min(dp(i-1,0),dp(i-1,1))+S[i]==R dp(i,1)=min(dp(i−1,0),dp(i−1,1))+S[i]==R
d p ( i , 2 ) = m i n ( d p ( i − 1 , 1 ) , d p ( i − 1 , 2 ) ) + S [ i ] = = B dp(i,2) = min(dp(i-1,1),dp(i-1,2))+S[i]==B dp(i,2)=min(dp(i−1,1),dp(i−1,2))+S[i]==B
class Solution {
public:
int dp[100005][5];
int minimumOperations(string a) {
int n = a.size();
dp[1][1] = (a[0] == 'y');
dp[1][2] = 1e8;
dp[1][3] = 1e8;
for (int i = 2 ; i <= n ; i++){
char g = a[i - 1];
dp[i][1] = dp[i - 1][1] + (g == 'y');
dp[i][2] = min (dp[i - 1][1] , dp[i - 1][2]) + (g == 'r');
dp[i][3] = min (dp[i - 1][2] , dp[i - 1][3]) + (g == 'y');
}
return dp[n][3];
}
};
题意:
给你一个数轴,你最开始站在0点.在每一个点X你可以选择向前走,向后走,或者搭乘公交i: X − > j u m p [ i ] × X X -> jump[i] \times X X−>jump[i]×X.每一种操作都有他们自己的花费。求从0到T点的最小花费.( 公交个数 ≤ 10 公交个数\leq10 公交个数≤10, 坐标 T ≤ 1 e 9 坐标T\leq1e9 坐标T≤1e9).
题目思路:
这道题的处理难点在于T过于庞大。如果直接跑Dijstra或会导致超时,因为本质上他是在搜索空间里做dp,那关键点在于如何减少不必要的搜索空间
①考虑一个子问题:若没有+1,-1的操作,只考虑坐公交的操作(保证有解)
正向思考比较困难,考虑到一定有解。那么不妨自顶向下的考虑。从T开始,若 T % j u m p [ i ] = = 0 T\% jump[i]==0 T%jump[i]==0.那么递归到 T j u m p [ i ] \frac{T}{jump[i]} jump[i]T点尝试求解(显然,自顶向下时我们是再考虑上一步从哪里来的,那些不能整除T的公交一定不可能是上一步).再加上记忆化即可
而且由于是做除法,那么最多 l o g min { j u m p [ i ] } T \ log_{\min{\{jump[i]\}}}T logmin{jump[i]}T 步能够到达1点.
②再来考虑有+1,-1的情况:
还是自顶向下的考虑,但这两种决策我们一定不能把他考虑进dp的决策里,不然搜索空间就爆炸了.
这时我们发现一个点:有了+1,-1操作之后,那些 T % j u m p [ i ] ≠ 0 T\%jump[i]\neq0 T%jump[i]=0的点也能放入决策中了!因为我们可以通过+1/-1来移动到jump[i]的整除点!这样以来+1/-1的作用仅仅就是将当前位置转移到 每个jump[i]的整除点了!到这里问题基本就解决了.
#define ll long long
class Solution {
public:
unordered_map<ll,ll>dp;
ll costl , costr;
ll dfs (ll x , vector<int>& a, vector<int>& b)
{
if (x == 1) return costr;
if (dp.find(x) != dp.end()) return dp[x];
ll ans = dfs (1 , a , b) + (x - 1) * costr;
for (int i = 0 ; i < a.size() ; i++){
if (x >= a[i]) ans = min (ans , dfs(x / a[i] , a , b) + b[i] + (x % a[i]) * costr );
ans = min (ans , dfs((x - 1) / a[i] + 1, a , b) + b[i] + (a[i] - (x % a[i])) * costl);
}
return dp[x] = ans;
}
int busRapidTransit(int s, int r, int l, vector<int>& a, vector<int>& b) {
costl = l;
costr = r;
int mod = 1e9 + 7;
return dfs(s , a , b) % mod;
}
};
题意:
给你一颗基环树,两个人在树上博弈,一个人追另一个人。设追逐者为A,被追逐者为B。A先动,问最少多少回合A能够追到B。或者输出-1代表永远无法追到.
思路:
一道挺思维的题.由于是基环树,所以只有一个环,那么在纸上画画图找规律不难想到
当开始时两者相邻,则1回合结束战斗
当环的大小=3时,必能被追到.
当环的大小 ≥ 4 \geq 4 ≥4时,若开始B在环上或者B能够在A抓到B之间到达环上,就永远追不到.反之必能被追到.
所以在B必能被抓到的情况下,B优先跑到离A最远的点i,且点i满足 d i s t B [ i ] + 1 < d i s t A [ i ] dist_B[i]+1
过程涉及到找环以及求单源最短路,考虑使用dfs和bfs求解。还有一些细节可以看看代码.
const int maxn = 100005;
const int inf = 1e9;
class Solution {
public:
vector<int> E[maxn];
int book[maxn] , dep[maxn] ,iscir[maxn] , dist_s[maxn] , dist_e[maxn] , n;
int cir_len;
stack<int> vis;
void findcir(int u , int fa , int step)
{
book[u] = 1;
dep[u] = step;
vis.push(u);
for (auto v : E[u]){
if (v == fa) continue;
if (book[v] == 2) continue;
// 遇到环
if (book[v] == 1){
cir_len = step - dep[v] + 1;
// 标记环上节点
iscir[v] = true;
stack<int> temp;
while (vis.top() != v) {
int g = vis.top();vis.pop();
iscir[g] = true;
temp.push(g);
}
while (temp.size()){
int g = temp.top();temp.pop();
vis.push(g);
}
continue;
}
findcir (v , u , step + 1);
}
book[u] = 2;
vis.pop();
}
void bfs (int s , int dist[])
{
for (int i = 1 ; i <= n ; i++) dist[i] = inf;
dist[s] = 0;
queue<int> q;
q.push(s);
while (q.size()){
int u = q.front(); q.pop();
for (auto v : E[u])
if (dist[v] == inf || dist[v] > dist[u] + 1)
dist[v] = dist[u] + 1 , q.push(v);
}
}
int chaseGame(vector<vector<int>>& edges, int s, int e) {
n = edges.size();
for (auto g : edges){
E[g[0]].push_back(g[1]);
E[g[1]].push_back(g[0]);
}
for (auto v : E[s]) if (v == e) return 1;
findcir(1 , 0 , 0);
bfs (s , dist_s);
bfs (e , dist_e);
if (cir_len == 3){
// 在三元环内部会让距离减少1
int gap = 0;
if (iscir[e]) {
bool ok = true;
for (auto v : E[e]){
if (iscir[v] == false) {
ok = false;
break;
}
}
gap = ok;
}
if (dist_s[e] - gap == 1) return 2;
// 现在找一个点使得 dist_s > dist_e + 1 的 离 dist_s 最远的点
int maxx = 0;
for (int i = 1 ; i <= n ; i++){
if (dist_s[i] > dist_e[i] + 1){
if (maxx < dist_s[i]){
maxx = dist_s[i];
}
}
}
return maxx;
}
// 初始化在环上,则永远无法遇到
// cout << iscir[e] << endl;
// for (auto v : E[50]) cout << v << " ";
// cout << endl;
if (iscir[e]) return -1;
// 不在环上,那看小扣能不能比小力先到环上任意一个点
for (int i = 1 ; i <= n ; i++){
if (iscir[i] == false) continue;
if (dist_s[i] > dist_e[i] + 1) {
// cout << "g " << endl;
return -1;
}
}
// 不行的话就找一个点使得 dist_s > dist_e + 1 的 离 dist_s 最远的点
int maxx = 0;
for (int i = 1 ; i <= n ; i++){
if (dist_s[i] > dist_e[i] + 1){
if (maxx < dist_s[i]){
maxx = dist_s[i];
}
}
}
return maxx;
}
};