淘天笔试 - 研发 0322 题解

T1

模拟,排序

  • 注意成绩相同按编号从小到大排序,以及保留两位小数
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    vector<int> a(n), sc(n, 10);
    vector b(n, vector<int>(m));
    for (auto &x : a) scanf("%d", &x);
    for (auto &v : b) for (auto &x : v) scanf("%d", &x);
    for (int k, x, i = 0; i < m; ++i) {
        scanf("%d", &k);
        while (k--) scanf("%d", &x), --x, !b[x][i] ? --sc[x] : 0;
    }
    vector<pair<int, int>> ans(n);
    for (int i = 0; i < n; ++i) ans[i] = {40 * max(0, sc[i]) + 6 * a[i], -i};
    sort(ans.begin(), ans.end(), greater<>());
    for (auto [x, y] : ans)
        printf("%d %.2lf\n", -y + 1, x * 0.1);
    return 0;
}

T2

个字符串,任意删除一个非空区间的字符串,最大化完全相同字符串的区间长度。

  • 字符串哈希转换为数字序列
  • 预处理 表示上一个/下一个哈希值不等于 的位置
  • 对于一个分段点 ,答案为
  • set 维护相同 的连续段长度
  • 从后往前枚举分段点 ,将 中删除,统计答案
  • 注意边界条件,
#include <bits/stdc++.h>
using namespace std;
const int B = 97, P = 1e9 + 7;
const int N = 1e6 + 5;
int pw[N]; char str[N];
int main() {
   pw[0] = 1;
   for (int i = 1; i < N; ++i) pw[i] = 1ll * pw[i - 1] * B % P;
   int n, m = 0, ans = 1;
   scanf("%d", &n);
   vector<int> a(n);
   unordered_map<int, int> mp;
   for (int i = 0; i < n; ++i) {
       scanf("%s", str);
       int L = strlen(str), &k = a[i];
       for (int j = 0; j < L; ++j)
           k = (1ll * k * B + str[j] - 'a') % P;
       if (!mp.count(k)) mp[k] = m++;
       k = mp[k];
   }
   vector<int> pre(n), nxt(n);
   pre[0] = -1, nxt[n - 1] = n;
   for (int i = 1; i < n; ++i)
       if (a[i] == a[i - 1]) pre[i] = pre[i - 1];
       else pre[i] = i - 1;
   for (int i = n - 2; i >= 0; --i)
       if (a[i] == a[i + 1]) nxt[i] = nxt[i + 1];
       else nxt[i] = i + 1;
   map<int, set<pair<int, int>>> f;
   for (int i = 0; i < n; ++i)
       f[a[i]].insert({i - pre[i], i});
   for (int i = n - 1; i >= 0; --i) {
       f[a[i]].erase({i - pre[i], i});
       int res = i < n - 1 ? nxt[i + 1] - (i + 1): 0;
       if (0 < i && i + 1 < n && !f[a[i + 1]].empty())
           res += f[a[i + 1]].rbegin()->first;
       ans = max(ans, res);
   }
   printf("%d\n", ans);
   return 0;
}

T3

个人依次采矿,第 个人会采集所有深度不超过 的矿物; 个矿脉,第 个矿脉在深度 都有 1 单位矿物。问每个人分别能采集多少单位矿物?

  • 排序,如果 ,则有:

  • 每次更新 ,双指针维护 upper_bound 即可。

#include <bits/stdc++.h>
using namespace std;
using ll = int64_t;
int main() {
   int n, m;
   scanf("%d%d", &n, &m);
   vector<int> a(n), b(m);
   vector<ll> ans(n);
   for (auto &x : a) scanf("%d", &x);
   for (auto &x : b) scanf("%d", &x);
   sort(b.begin(), b.end());
   for (int i = 0, j = 0, h = 0; i < n && j < m; ++i) {
       if (a[i] <= h) continue;
       ll &sum = ans[i];
       while (j < m && a[i] >= b[j]) sum += b[j++] - h;
       sum += 1ll * (m - j) * (a[i] - h), h = a[i];
   }
   for (auto x : ans) printf("%lld ", x);
   return 0;
}
#笔试##淘天##淘天26届春招##牛客创作赏金赛#
全部评论

相关推荐

03-15 20:26
已编辑
电子科技大学 C++
T3题面:给一个3e5数组,每次询问长度为len的子数组乘积的和,如果子数组乘积&gt;1e9,则视为0.赛后一分钟想出来了,比赛时打了个暴力+线段树注意到1e9大约是2^30,&nbsp;因此len长度如果&gt;30就直接输出0,30以内做一个记忆化就行,复杂度O(30*n)感觉是以前比赛做过的题,忘了怎么做了。。。---upd:&nbsp;忘了数据范围了,如果有0,1的话那这样也不行
blueswiller:给出一个做法,刚刚才想到,应该没问题,时间复杂度为 O(max(30n, nlogn)): 1. 根据 0 切分数组。2. 现在问题转化为>=1 的情况,我们首先维护每一个数前一个 > 1 的数的位置,同时维护一个长度的差分数组,初始值全为 0。3. 我们从每一个数 i 开始向前跳,至多跳 30 次,维护这个过程中的乘积,于是得到 30 个区间加和。举例:假设从 j1 跳到 j2 ,相当于对查询长度 (i- j1 + 1) 至 (i - j2) 贡献 a_i * ... * a_j1。4. 对于所有区间加和,我们采用差分数组结合树状数组对其进行维护,由于长度至多为 n ,树状数组构建的复杂度为 O(nlogn),于是,构建阶段的复杂度为 O(max(30n, nlogn))。在线单次查询的复杂度为树状数组查询的复杂度 O(logn)。
投递淘天集团等公司10个岗位 > 笔试
点赞 评论 收藏
分享
投递淘天集团等公司10个岗位
点赞 评论 收藏
分享
评论
2
2
分享

创作者周榜

更多
牛客网
牛客企业服务