0929字节笔试ak
字节的复活赛都输了,感觉身边拿字节offer都没走笔试程序,寄!
1:给定一个数组,使用双端队列按照顺序存(每次可以放到头或者尾),放完后双端队列能否非降序排列。
模拟+贪心:题目要求非降序,每次放的判断跟队列头尾比较就行,每次都要满足比头小或者比尾大。
n=(1e5),O(n)
#include "bits/stdc++.h"
using namespace std;
int main()
{
int T;
cin >> T;
while (T--)
{
int n;
scanf("%d", &n);
deque<int> dq;
bool flag = true;
while (n--)
{
int tmp;
scanf("%d", &tmp);
if (flag)
{
if (dq.empty())
dq.push_back(tmp);
else if (dq.front() >= tmp)
dq.push_front(tmp);
else if (dq.back() <= tmp)
dq.push_back(tmp);
else
flag = false;
}
}
if (flag)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
2:给定n,从1开始,每a天执行一件事,每b天执行一件事,每c天执行一件事。问有多少天干了至少2件事。
三个集合相交:(a∩b)∪(a∩c)∪(b∩c)-2(a∩b∩c)
n=(1e5),O(n)
#include "bits/stdc++.h"
using namespace std;
int main()
{
int T;
cin >> T;
while (T--)
{
int n, a, b, c;
scanf("%d %d %d %d", &n, &a, &b, &c);
int ab = a * b / gcd(a, b);
int ac = a * c / gcd(a, c);
int bc = b * c / gcd(b, c);
int abc = ab * c / gcd(ab, c);
int sum = 0;
sum += n / ab;
sum += n / ac;
sum += n / bc;
sum -= 2 * (n / abc);
printf("%d\n", sum);
}
return 0;
}
3:给一个数组a(从1开始,每个元素都是[1,n]),可以从i到(i+1)和(i-1),开销是1。i到(i+a[i]),开销是abs(a[i]-a[i+a[i]))。从1开始,求到每个点的最小开销。
Dijkstra:抽象成图,跑一遍Dijkstra即可(太久没写最短路了,调了快50分钟)
n=(2e5),m是图中边的数目,该题m=3n=O(n)。O(mlog(m))=O(nlog(n))
#include "bits/stdc++.h"
using namespace std;
int main()
{
int n;
scanf("%d", &n);
vector<int> arr(n + 1, 0);
vector<int> dis(n + 1, n);
vector<set<pair<int, int>>> edges(n + 1);
for (int i = 1; i <= n; i++)
scanf("%d", &arr[i]);
for (int i = 1; i <= n; i++)
{
int j = i - 1;
if (j >= 1)
edges[i].insert(make_pair(j, 1));
j = i + 1;
if (j <= n)
edges[i].insert(make_pair(j, 1));
j = i + arr[i];
if (j <= n)
edges[i].insert(make_pair(j, abs(arr[i] - arr[j])));
}
auto dijkstra = [&](int s)
{
vector<bool> vis(n + 1, false);
dis[s] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>>
pq;
pq.push(make_pair(dis[s], s));
while (!pq.empty())
{
auto top = pq.top();
pq.pop();
int d = top.first, u = top.second;
if (vis[u])
continue;
vis[u] = true;
for (auto iter : edges[u])
{
int v = iter.first, w = iter.second;
if (dis[v] > d + w)
{
dis[v] = d + w;
pq.push(make_pair(dis[v], v));
}
}
}
};
dijkstra(1);
for (int i = 1; i <= n; i++)
printf("%d ", dis[i]);
return 0;
}
4:给一个数组a,只有一个最大值的子数组称为完美子数组。求完美子数组的个数
复杂二分:从大到小遍历,每次遍历当前值的所有位置,用二分找到该位置能组成的完美子数组个数(左边prev(lower_bound),右边upper_bound)
n=(1e5)。O(nlog(n))
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
int main()
{
int n;
scanf("%d", &n);
vector<int> arr(n, 0);
for (int i = 0; i < n; i++)
scanf("%d", &arr[i]);
ll ans = 0;
map<int, set<int>> ump;
set<int> st;
for (int i = 0; i < n; i++)
ump[arr[i]].insert(i);
for (auto iter = ump.rbegin(); iter != ump.rend(); iter++)
{
for (auto index : iter->second)
st.insert(index);
for (auto index : iter->second)
{
auto l_iter = st.lower_bound(index);
auto r_iter = st.upper_bound(index);
int l = index, r = index;
if (l_iter == st.begin())
l = index + 1;
else
l = index - *(--l_iter);
if (r_iter == st.end())
r = n - index;
else
r = *r_iter - index;
ans += ll(l) * r;
}
}
cout << ans << endl;
return 0;
}
带哨兵节点的版本
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
int main()
{
int n;
scanf("%d", &n);
vector<int> arr(n, 0);
for (int i = 0; i < n; i++)
scanf("%d", &arr[i]);
ll ans = 0;
map<int, set<int>> ump;
set<int> st;
// 哨兵节点
st.insert(-1);
st.insert(n);
for (int i = 0; i < n; i++)
ump[arr[i]].insert(i);
for (auto iter = ump.rbegin(); iter != ump.rend(); iter++)
{
for (auto index : iter->second)
st.insert(index);
for (auto index : iter->second)
ans += ll(index - *(--st.lower_bound(index))) * (*st.upper_bound(index) - index);
}
cout << ans << endl;
return 0;
}
#25秋招##字节笔试#
顺丰集团工作强度 316人发布
