小红书笔试 20250824

笔试时间:2025年8月24日

往年笔试合集:

2023春招秋招笔试合集

2024春招秋招笔试合集

第一题:行为权重

小红是小红书的用户行为分析师。平台将每次用户行为映射为一个正整数权重序列 [a₁, a₂, …, aₙ],以便后续关联推荐时关键 “红色” 行为。

为了保证标记的行为具有足够的共性,必须选出的所有 “红色” 行为权重的最大公约数大于 1;同时,为了避免相邻生冗余,所选下标不得相邻。

现给定用户的一次行为序列,求最多可以染成红色的行为数量。

【名词解释】

最大公约数:指一组整数共有约数中最大的一个。例如,12、18 和 30 的公约数有 1,2,3,6,其中最大的约数是 6,因此 gcd (12,18,30)=6。

输入描述

在一行上输入一个整数 n(1 ≤ n ≤ 10⁵),表示行为序列长度。

在第二行输入 n 个整数 a₁, a₂, …, aₙ(1 ≤ aᵢ ≤ 100),表示每次行为的权重值。

输出描述

在一行上输出一个整数,表示最多可染红的行为数量。

样例输入

5 1 2 3 2 6

样例输出

2

在这个样例中,可将下标 2 与 4 对应的权重染红,它们的最大公约数为 2,且不相邻,故答案为 2。

参考题解

直接找出满足所有条件的最佳组合很复杂。我们可以反过来想:既然所有选中的数必须有一个大于1的最大公约数(GCD),那么它们必然都是某个整数 d (d>1) 的倍数。由于题目给的数字最大不超过100,这个公约数 d 也肯定在2到100之间。因此,我们可以把复杂问题分解成近百个简单问题:第一步:锁定公约数 d我们假设最终选出的所有“红色”行为,它们的公约数就是 d。我们依次让 d 等于 2、3、4、...、100,分别计算每种情况下的最优解。第二步:解决简化后的问题 当公约数 d 固定后,问题就变成了:在原数组中,最多能选出多少个“不相邻”的、且是 d 的倍数的数?第三步:动态规划(“打家劫舍”模型)这个简化后的问题是一个非常经典的动态规划模型,可以类比为“打家劫舍”(不能偷相邻的屋子)。 我们从头到尾遍历数组,对每个位置 i 的数 a[i],我们做决策:不选 a[i]:最大数量等于到位置 i-1 的最大数量。选 a[i]:因为不能和相邻的 a[i-1] 一起选,所以最大数量是 1 (代表 a[i] 自己) + 到位置 i-2 的最大数量。我们在这两个选择中取一个更大的结果。如果 a[i] 不是 d 的倍数:我们肯定不能选它,所以到位置 i 为止的最大数量,就等于到位置 i-1 的最大数量。如果 a[i] 是 d 的倍数:我们有两个选择:第四步:取全局最优解我们对每一个 d(从2到100)都执行一次第三步的动态规划,会得到近百个结果。在所有这些结果中,取那个最大的数,就是题目的最终答案。

C++:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    
    int ans = 0;
    
    for (int d = 2; d <= 100; ++d) {
        int prev1 = 0, prev2 = 0;
        for (int i = 0; i < n; ++i) {
            int temp1 = prev2;
            int temp2 = 0;
            
            if (a[i] % d == 0) {
                temp2 = 1 + prev1;
            }
            
            int current = max(temp1, temp2);
            prev1 = prev2;
            prev2 = current;
        }
        
        if (prev2 > ans) {
            ans = prev2;
        }
    }
    
    cout << ans << endl;
    
    return 0;
}
    

Java:

import java.util.Scanner;

public class MaxDivisibleSubsequence {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        int n = scanner.nextInt();
        int[] a = new int[n];
        
        for (int i = 0; i < n; ++i) {
            a[i] = scanner.nextInt();
        }
        
        int ans = 0;
        
        for (int d = 2; d <= 100; ++d) {
            int prev1 = 0, prev2 = 0;
            for (int i = 0; i < n; ++i) {
                int temp1 = prev2;
                int temp2 = 0;
                
                if (a[i] % d == 0) {
                    temp2 = 1 + prev1;
                }
                
                int current = Math.max(temp1, temp2);
                prev1 = prev2;
                prev2 = current;
            }
            
            if (prev2 > ans) {
                ans = prev2;
            }
        }
        
        System.out.println(ans);
        scanner.close();
    }
}
    

Python:

import sys

def main():
    n = int(sys.stdin.readline())
    a = list(map(int, sys.stdin.readline().split()))
    ans = 0
    
    for d in range(2, 101):
        prev1, prev2 = 0, 0
        for i in range(n):
            temp1 = prev2
            temp2 = 0
            if a[i] % d == 0:
                temp2 = 1 + prev1
            current = max(temp1, temp2)
            prev1, prev2 = prev2, current
        if prev2 > ans:
            ans = prev2
    
    print(ans)

if __name__ == "__main__":
    main()

第二题:潜在同好

在小红书平台的社交推荐项目中,产品团队希望基于用户的日常行为习惯分数,挖掘潜在的 “同好” 关系。系统简化如下,数据库中有 n 个用户的日常行为习惯分数,第 i 个用户的分数使用 aᵢ表示。记第 i 个用户和第 j 个用户构成 “同好” 关系,当且仅当 aᵢ能被 aⱼ整除,或者 aⱼ能被 aᵢ整除。接下来将进行 m 次查询,每次给定一个额外的用户行为分数 x,请统计在数据库中,有多少不同的人能与这个人构成 “同好” 关系。

输入描述

第一行输入两个整数 n,m(1 ≤ n,m ≤ 5×10⁵),表示数据库中用户数量、查询次数。

第二行输入 n 个整数 a₁,a₂,…,aₙ(1 ≤ aᵢ ≤ 5×10⁵),表示数据库中的用户日常行为习惯分数。

接下来 m 行,每行输入一个整数 x(1 ≤ x ≤ 5×10⁵),表示一个额外的用户行为习惯分数。

输出描述

对于每次查询,新起一行,输出一个整数,表示数据库中能与 x 构成 “同好” 关系的用户数量。

样例输入

5 3

1 2 2 5 6

4

2

1

样例输出

3

4

5

参考题解

预处理 + 容斥原理。核心公式对于每次查询 x,与其构成“同好”关系的人数等于: (数据库中 x 的倍数个数) + (数据库中 x 的因数个数) - (数据库中 x 自身的个数) 减去 x 自身的个数是因为它在“倍数”和“因数”中被计算了两次。优化方法直接对每次查询计算上述数量会超时。由于查询次数多而数值范围固定,我们采用“空间换时间”的策略,进行预处理。预处理步骤我们使用三个数组,提前算好所有可能用到的信息:这两个关键数组 (multiples_count 和 divisors_sum) 都可以通过类似筛法的循环在 O(MAXlogMAX) 的高效时间内计算完成。counts[k]: 统计分数 k 的出现次数。multiples_count[k]: 预计算数据库中 k 的倍数总共有多少个。divisors_sum[k]: 预计算数据库中 k 的因数总共有多少个。快速查询 预处理完成后,对于任何查询 x,我们只需从预处理好的数组中直接取值,代入第一步的核心公式,即可在 O(1) 时间内得出答案。

C++:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

const int M = 500001;

vector<int> f1(int n, vector<int>& arr, int sz) {
    vector<int> cnt(sz + 1, 0);
    for (int v : arr) {
        if (v <= sz) {
            cnt[v]++;
        }
    }
    return cnt;
}

vector<int> f2(vector<int>& cnt, int sz) {
    vector<int> mc(sz + 1, 0);
    for (int i = 1; i <= sz; ++i) {
        int t = i;
        while (t <= sz) {
            mc[i] += cnt[t];
            t += i;
        }
    }
    return mc;
}

vector<int> f3(vector<int>& cnt, int sz) {
    vector<int> ds(sz + 1, 0);
    for (int i = 1; i <= sz; ++i) {
        if (cnt[i] > 0) {
            int j = i;
            while (j <= sz) {
                ds[j] += cnt[i];
                j += i;
            }
        }
    }
    return ds;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n_val, m_val;
    cin >> n_val >> m_val;
    
    vector<int> nums(n_val);
    for (int i = 0; i < n_val; ++i) {
        cin >> nums[i];
    }
    
    vector<int> cnt_arr = f1(n_val, nums, M);
    vector<int> mc_arr = f2(cnt_arr, M);
    vector<int> ds_arr = f3(cnt_arr, M);
    
    vector<string> output;
    for (int i = 0; i < m_val; ++i) {
        int q;
        cin >> q;
        if (q >= M) {
            output.push_back("0\n");
        } else {
            int result = mc_arr[q] + ds_arr[q] - cnt_arr[q];
            output.push_back(to_string(result) + "\n");
        }
    }
    
    for (const string& line : output) {
        cout << line;
    }
    
    return 0;
}
    

Java:

import java.io.*;
import java.util.*;

public class ArrayAnalyzer {
    private static final int M = 500001;

    public static int[] f1(int n, int[] arr, int sz) {
        int[] cnt = new int[sz + 1];
        for (int v : arr) {
            if (v <= sz) {
                cnt[v]++;
            }
        }
        return cnt;
    }

    public static int[] f2(int[] cnt, int sz) {
        int[] mc = new int[sz + 1];
        for (int i = 1; i <= sz; i++) {
            int t = i;
            while (t <= sz) {
                mc[i] += cnt[t];
                t += i;
            }
        }
        return mc;
    }

    public static int[] f3(i

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

2025 春招笔试合集 文章被收录于专栏

2025打怪升级记录,大厂笔试合集 C++, Java, Python等多种语言做法集合指南

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务