小红书笔试 4.9 算法岗(3/3 附题面)

题面在代码中

A. 平衡

和昨晚的美团笔试差不多,先一遍dfs处理以sz[i], 得到以 i 为根的子树大小,枚举边求答案即可。

/*
小红书 23届补录&24届实习 【24届实习】算法笔试
*/
#include<bits/stdc++.h>

#define debug(x) std::cerr << x << '\n';
#define all(x) x.begin(), x.end()

using i64 = long long;
using pii = std::pair<int, int>;
using vi = std::vector<int>;
using vp = std::vector<pii>;
using vl = std::vector<i64>;

struct Edge {
  int u, v;
} edge[1000005];
vi G[1000005];
int sz[1000005];
void dfs(int u, int par) {
  sz[u] = 1;
  for (auto v : G[u]) {
    if (v == par) {
      continue;
    }
    dfs(v, u);
    sz[u] += sz[v];
  }
}
int ans[1000005], fa[1000005];
void solve() {
  int n;
  std::cin >> n;
  for (int i = 1; i <= n - 1; i++) {
    int u, v;
    std::cin >> u >> v;
    G[u].emplace_back(v);
    G[v].emplace_back(u);
    edge[i].u = u, edge[i].v = v;
    fa[u] = v;
  }
  int root = 1;
  for (int i = 1; i <= n; i++) {
    if (!fa[i]) {
      root = i;
    }
  }
  dfs(root, 0);
  int res = 1e9;
  for (int i = 1; i <= n - 1; i++) {
    int u = edge[i].u, father = edge[i].v;
    int now = std::abs(sz[u] - (n - sz[u]));
    ans[now]++;
    res = std::min(res, now);
  }
  std::cout << res << ' ' << ans[res] << '\n';
}

int main() {
  std::cin.tie(nullptr) -> sync_with_stdio(false);
  int T = 1;
  //std::cin >> T;
  while (T--) {
    solve();
  }
  return 0;
}
/*
平衡
时间限制: 1000MS
内存限制: 65536KB
题目描述:
输入一棵树 T,你需要删除一条边,这棵树会被分成A 和 B 两棵树。你需要让两部分的节点数的差的绝对值| |A|-|B| |尽可能小。输出最小的| |A|-|B| |和最优方案的数量。



输入描述
第一行一个整数 n表示节点的数量,节点从1 到 n编号。

接下来n-1行每行两个正整数 s t,表示s的父亲是t。

输入保证是一棵树。

对于所有数据 1<=n<=100000。

输出描述
输出一行,两个整数,用空格分开,分别表示最优解和最优方案数。


样例输入
3
2 1
3 1
样例输出
1 2
*/

B. 配制溶液

要配置体积为V的溶液,可以枚举子状态 i 和 V - i, 其实就是求子状态的最优策略,所以可以递归做,类似于记忆化搜索。

/*
小红书 23届补录&24届实习 【24届实习】算法笔试
*/
#include<bits/stdc++.h>

#define int long long
#define debug(x) std::cerr << x << '\n';
#define all(x) x.begin(), x.end()

using i64 = long long;
using pii = std::pair<int, int>;
using vi = std::vector<int>;
using vp = std::vector<pii>;
using vl = std::vector<i64>;

int A[1005], B[1005];
int dp[1005][1005];
int Max[1005], f[1005];
int n, X, C;

int dfs(int now) {
  if (f[now] != -1) {
    return f[now];
  }
  int ans = 0;
  for (int i = 1; i <= now - 1; i++) {
    if (!dfs(i) or !dfs(now - i)) {
      continue;
    }
    if (i == now - i) {
      ans = std::max(ans, dfs(i) + dfs(now - i) + X);
    } else {
      ans = std::max(ans, dfs(i) + dfs(now - i));
    }
  }
  return f[now] = std::max(Max[now], ans);
}
void solve() {
  memset(f, -1, sizeof(f));
  std::cin >> n >> X >> C;
  for (int i = 1; i <= n; i++) {
    std::cin >> A[i];
  }
  for (int i = 1; i <= n; i++) {
    std::cin >> B[i];
    Max[A[i]] = std::max(Max[A[i]], B[i]);
  }
  for (int i = 1; i <= C; i++) {
    std::cerr << i << ' ' << dfs(i) << '\n';
  }

  std::cout << dfs(C) << '\n';
}

signed main() {
  std::cin.tie(nullptr) -> sync_with_stdio(false);
  int T = 1;
  //std::cin >> T;
  while (T--) {
    solve();
  }
  return 0;
}
/*
配制溶液
时间限制: 3000MS
内存限制: 589824KB
题目描述:
实验室需要配制一种溶液。现在,研究员面前有n种该物质的溶液,每一种有无限多瓶,第i种的溶液体积为xi,里面含有yi单位的该物质。研究员每次可以选择一瓶溶液,将其倒入另外一瓶(假设瓶子的容量无限),即可以看作将两个瓶子内的溶液合并。此时合并的溶液体积和物质含量都等于之前两个瓶子内的之和。

特别地,如果瓶子A与B的溶液体积相同,那么A与B合并之后该物质的含量会产生化学反应,使得该物质含量增加X单位。

研究员的任务是配制溶液体积恰好等于C的,且尽量浓的溶液(即物质含量尽量多)。研究员想要知道物质含量最多是多少。



输入描述
第一行三个正整数n,X,C;

第二行n个正整数x1,x2,...,xn,中间用空格隔开;

第三行n个正整数y1,y2,...,yn,中间用空格隔开。

对于所有数据,1≤n,X,C,yi≤1000,1≤xi≤C

数据保证至少存在一种方案能够配制溶液体积恰好等于C的溶液。

输出描述
输出一行一个整数,表示答案。


样例输入
3 4 16
5 3 4
2 4 1
样例输出
29
*/

C. 双色球

有个小坑:当红球在袋子里的时候,每过去一秒上面的数字就会增加1,蓝球上的数字则会减少1。

一开始没注意到,wa了很多次。我们只需要记录当前放了多少个红和蓝,记录编号为id的小球放进去的时间就可以了。

/*
小红书 23届补录&24届实习 【24届实习】算法笔试
*/
#include<bits/stdc++.h>

#define int long long


#define debug(x) std::cerr << x << '\n';
#define all(x) x.begin(), x.end()

using i64 = long long;
using pii = std::pair<int, int>;
using vi = std::vector<int>;
using vp = std::vector<pii>;
using vl = std::vector<i64>;

int A[500005], B[1000005], C[1000005], in[1000005];
std::string color;

void solve() {
  int n;
  while (std::cin >> n) {
  //std::cin >> n;
  i64 sum = 0;
  int red = 0, blue = 0;
  for (int i = 1; i <= n; i++) {
    std::cin >> A[i];
  }
  std::cin >> color;
  color = ' ' + color;
  int m;
  std::cin >> m;
  for (int i = 1; i <= m; i++) {
    std::cin >> B[i];
  }
  for (int i = 1; i <= m; i++) {
    std::cin >> C[i];
  }
  for (int i = 2; i <= m; i++) {
    assert(B[i] > B[i - 1]);
  }
  int Nowtime = 0;
  memset(in, -1, sizeof(in));
  std::vector<i64> ans;
  for (int i = 1; i <= m; i++) {
    int TimeDet = B[i] - Nowtime;
    sum += red * TimeDet;
    sum -= blue * TimeDet;
    if (C[i] == 0) {
      ans.emplace_back(sum);
    } else {
      int id = std::abs(C[i]);
      if (C[i] > 0) {
        assert(in[id] == -1);
        sum += A[id];
        in[id] = B[i];
        red += color[id] == 'R';
        blue += color[id] == 'B';
      } else if (C[i] < 0) {
        sum -= A[id];
        sum -= (color[id] == 'R' ? 1 : -1) * (B[i] - in[id]);
        A[id] = (A[id] + (color[id] == 'R' ? 1 : -1) * (B[i] - in[id]));
        red -= color[id] == 'R';
        blue -= color[id] == 'B';
        in[id] = -1;
      }
    }
    //std::cerr << i << ' ' << sum << '\n';
    Nowtime = B[i];
  }
  std::cout << ans.size();
  for (auto iter : ans) {
    std::cout << ' ' << iter;
  }
  std::cout << '\n';
  }
}

signed main() {
  std::cin.tie(nullptr) -> sync_with_stdio(false);
  int T = 1;
  //std::cin >> T;
  while (T--) {
    solve();
  }
  return 0;
}
/*
 
时间限制: 3000MS
内存限制: 589824KB
题目描述:
小明有一个神奇的袋子和一堆编号为1到n的球。每个球都被涂成了红色或者蓝色,且这些球的表面上都分别写着一个数字。

当红球在袋子里的时候,每过去一秒上面的数字就会增加1,蓝球上的数字则会减少1。

小明会时不时向袋子里放入球或取出球,并且他想知道某些时刻袋子中球上写的数字之和。



输入描述
第一行有一个正整数n(1<=n<=5000),代表小明有几个球。

第二行有n个范围在[-1000000,1000000]内的整数,第i个代表编号为1到n的球上写的数。

第三行是一个长度为n的仅由`R`和`B`构成的字符串,第i个字母代表编号为i的球是红色(R)或蓝色(B)

第四行有一个正整数m(1<=m<=100000),代表小明进行了几次操作。

第五行有m个递增的正整数,第i个代表小明进行的第i次操作时间点。每个时间点小明只会进行至多一次操作。时间点的范围在[1,1000000000]内。

第六行有m个整数,第i个代表小明进行的操作。0为询问当前时间点袋中球上的数字之和,正数x代表放入了编号为x的球,负数-x代表取出了编号为x的球。

最开始袋子是空的。 你可以认为球上的数字变化均发生在时间点之前,而每次操作均发生在时间点之后。输入保证操作合法。

输出描述
设小明进行了k次询问。你需要在一行中先输出k,然后输出k个数,第i个代表第i次询问的答案。

题目保证小明进行过至少一次询问。


样例输入
3
-5 4 6
RBR
9
1 2 3 4 5 6 8 13 14
1 3 0 2 -3 0 -1 0 -2
样例输出
3 4 2 -5

3
1 1 1
RRB
4
1 2 3 10
1 3 -1 0
*/

#小红书##小红书实习招聘##小红书笔试##软件开发2023笔面经##小红书信息集散地#
一些比赛的题解 文章被收录于专栏

一些比赛的题解

全部评论
点赞 回复 分享
发布于 2023-04-09 18:03 广东
点赞 回复 分享
发布于 2023-04-09 18:20 辽宁
神!
点赞 回复 分享
发布于 2023-04-09 19:33 辽宁
阿里数字供应链部门刚开始春招,欢迎同学踊跃报表。查看个人首页帖子 查看部门介绍和扫码线上投递简历。 https://www.nowcoder.com/discuss/472422701500485632?
点赞 回复 分享
发布于 2023-04-10 11:16 浙江
楼主这代码风格 是竞赛选手吗??
点赞 回复 分享
发布于 2023-04-10 19:04 浙江

相关推荐

我已成为0offer的糕手:别惯着,胆子都是练出来的,这里认怂了,那以后被裁应届被拖工资还敢抗争?
点赞 评论 收藏
分享
17 69 评论
分享
牛客网
牛客企业服务