【笔试刷题】阿里系列-2026.03.28-算法岗-改编真题

✅ 春招备战指南 ✅

💡 学习建议:

  • 先尝试独立解题
  • 对照解析查漏补缺

🧸 题面描述背景等均已深度改编,做法和题目本质基本保持一致。

🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力

🌸 目前本专栏已经上线200+套真题改编解析,后续会持续更新的

春秋招笔试机考招合集 -> 互联网必备刷题宝典🔗

阿里系列-2026.03.28-算法岗

1. 小基 的回合净值对抗

先看单个位置对答案 的贡献。无论这个位置最后被谁拿走,贡献都是
因此整题只剩一次求和,顺序和策略都不会影响结果。

2. 小兰的双平方切分统计

先把不超过 的完全平方数全部枚举出来。
对每个平方数尝试切一刀,检查左右两段是不是也都是平方数,最后对结果表二分回答询问。

3. 小柯的差值阈值最长子段

把相邻差值看成边权,阈值 固定后,问题就是“保留权值不超过 的边时,链上最大连通块有多大”。
阈值从小到大扫一遍,用分桶 + 并查集增量合并即可。

01. 小基 的回合净值对抗

问题描述

给定两个长度为 的整数数组 ,共有 个位置可选,各自只能被选择一次。Alice 先手、Bob 后手,轮流选位。

  • Alice 选择位置 时,本回合净收益为
  • Bob 选择位置 时,本回合净收益为

设 Alice 的总净收益为 ,Bob 的总净收益为 。两人都采取最优策略,Alice 想最大化 ,Bob 想最小化 。请输出最终分差

输入格式

每个测试文件包含多组测试数据。

  • 第一行输入一个整数 ,表示测试数据组数。
  • 对于每组测试数据:
  • 第一行输入一个整数
  • 第二行输入 个整数
  • 第三行输入 个整数

输出格式

对于每组测试数据,输出一行一个整数,表示在最优博弈下的分差

样例输入

3
3
3 1 2
2 2 2
2
1 10
10 1
4
5 1 1 1
1 4 4 4

样例输出

0
0
-5

数据范围

  • 所有测试数据中 的总和不超过

题解

先别管“双方最优”这层外壳,先看每个位置对最终答案的贡献。

我们只看某个位置 对最终答案 的贡献。

  • 如果这个位置被 Alice 选走,那么 增加 ,所以 增加
  • 如果这个位置被 Bob 选走,那么 Bob 本回合净收益是 ,也就是 增加 。于是 变成 ,仍然增加

也就是说,不管这个位置最后落在谁手里,它对答案的贡献都固定是
每个位置都这样,整道题就只剩把这些贡献加起来。

所以答案直接就是

每组数据线性扫描一次即可,时间复杂度是 ,总复杂度是

参考代码

  • Python
import sys


def solve() -> None:
    data = sys.stdin.buffer.read().split()
    if not data:
        return

    t = int(data[0])
    idx = 1
    out = []

    for _ in range(t):
        n = int(data[idx])
        idx += 1

        # 先累加数组 a。
        sum_a = 0
        for _ in range(n):
            sum_a += int(data[idx])
            idx += 1

        # 再累加数组 b。
        sum_b = 0
        for _ in range(n):
            sum_b += int(data[idx])
            idx += 1

        # 每个位置的贡献都是固定的,所以答案就是总差值。
        out.append(str(sum_a - sum_b))

    sys.stdout.write("\n".join(out))


if __name__ == "__main__":
    solve()
  • Cpp
#include 
using namespace std;

using int64 = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;

        int64 sum_a = 0;
        int64 sum_b = 0;

        for (int i = 0; i < n; ++i) {
            int64 x;
            cin >> x;
            sum_a += x;
        }
        for (int i = 0; i < n; ++i) {
            int64 x;
            cin >> x;
            sum_b += x;
        }

        // 答案等于 sum(a_i - b_i)。
        cout << (sum_a - sum_b) << '\n';
    }
    return 0;
}
  • Java
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        FastScanner fs = new FastScanner(System.in);
        StringBuilder sb = new StringBuilder();

        int t = fs.nextInt();
        while (t-- > 0) {
            int n = fs.nextInt();
            long sumA = 0;
            long sumB = 0;

            for (int i = 0; i < n; i++) {
                sumA += fs.nextLong();
            }
            for (int i = 0; i < n; i++) {
                sumB += fs.nextLong();
            }

            // 每个位置对 A-B 的贡献固定,因此直接求总和。
            sb.append(sumA - sumB).append('\n');
        }

        System.out.print(sb);
    }

    static class FastScanner {
        private final InputStream in;
        private final byte[] buffer = new byte[1 << 16];
        private int ptr = 0;
        private int len = 0;

        FastScanner(InputStream is) {
            in = is;
        }

        private int read() throws IOException {
            if (ptr >= len) {
                len = in.read(buffer);
                ptr = 0;
                if (len <= 0) {
                    return -1;
                }
            }
            return buffer[ptr++];
        }

        int nextInt() throws IOException {
            return (int) nextLong();
        }

        long nextLong() throws IOException {
            int c;
            while ((c = read()) <= ' ') {
                if (c == -1) {
                    return -1;
                }
            }
            long sign = 1;
            if (c == '-') {
                sign = -1;
                c = read();
            }
            long val = 0;
            while (c > ' ') {
                val = val * 10 + c - '0';
                c = read();
            }
            return val * sign;
        }
    }
}

02. 小兰的平方拼接计数

问题描述

一个正整数称为“平方拼接数”当且仅当它自身是完全平方数,且某个相邻切分可以把十进制表示分成左右两段,两段都还是完全平方数。

  1. 它本身是一个完全平方数。
  2. 它的十进制表示可以在某个相邻位置切成左右两段,且这两段都非空,并且对应的十进制整数也都是完全平方数。

切分时不允许出现前导零,除非这一段本身就只有一个字符 0

例如, 是一个平方拼接数,因为它可以切成 ,其中 都是完全平方数。

给定上界 ,请你统计不超过 的平方拼接数有多少个。

输入格式

每个测试文件包含多组测试数据。

  • 第一行输入一个整数 ,表示数据组数。
  • 接下来 行,每行输入一个整数

输出格式

对于每组数据,输出一行一个整数,表示不超过 的平方拼接数个数。

样例输入

2
50
1500

样例输出

1
5

数据范围

题解

查询次数很少,而上界只有 ,这题最自然的做法就是先把所有候选数预处理出来。

因为一个平方拼接数自己必须先是完全平方数,所以我们只需要枚举

一共也就三万多个数。

对于某个平方数 ,把它转成字符串 。如果长度是 ,那么只可能在 这些位置切开。
假设切点在 ,那么:

  • 左半段是 s[0:p]
  • 右半段是 s[p:L]

我们需要检查三件事:

  1. 左段没有非法前导零;
  2. 右段没有非法前导零;
  3. 左右两段转成整数后,都是完全平方数。

只要某个切点合法,这个 就应该计入答案。

预处理完全部平方拼接数后,把它们放进有序数组里。
每次询问只要求不超过 的个数,直接用二分求出最后一个 的位置即可。

复杂度分析

  • 预处理时只枚举约 个平方数,每个数最多尝试十次切分,复杂度近似
  • 每次查询二分一次,复杂度 ,其中 是平方拼接数的总个数。

完全够用。

参考代码

  • Python
import bisect
import math
import sys


def is_square(x: int) -> bool:
    if x < 0:
        return False
    r = math.isqrt(x)
    return r * r == x


def build_good_numbers() -> list[int]:
    limit = int(math.isqrt(10**9))
    good = []

    for i in range(1, limit + 1):
        sq = i * i
        s = str(sq)
        if len(s) < 2:
            continue

        ok = False
        for p in range(1, len(s)):
            left_s = s[:p]
            right_s = s[p:]

            # 两段都不能出现非法前导零。
            if len(left_s) > 1 and left_s[0] == "0":
                continue
            if len(right_s) > 1 and right_s[0] == "0":
                continue

            left = int(left_s)
            right = int(right_s)
            if is_square(left) and is_square(right):
                ok = True
                break

        if ok:
            good.append(sq)

    return good


GOOD = build_good_numbers()


def solve() -> None:
    data = sys.stdin.buffer.read().split()
    if not data:
        return

    t = int(data[0])
    out = []
    for i in range(1, t + 1):
        n = int(data[i])
        # 二分统计 <= n 的个数。
        out.append(str(bisect.bisect_right(GOOD, n)))

    sys.stdout.write("\n".join(out))


if __name__ == "__main__":
    solve()
  • Cpp
#include 
using namespace std;

using int64 = long long;

bool isSquare(int x) {
    if (x < 0) {
        return false;
    }
    int r = (int) sqrt((long double) x);
    while (1LL * (r + 1) * (r + 1) <= x) {
        ++r;
    }
    while (1LL * r * r > x) {
        --r;
    }
    return 1LL * r * r == x;
}

vector buildGoodNumbers() {
    vector good;
    int limit = (int) sqrt(1e9);
    for (int i = 1; i <= limit; ++i) {
        int sq = i * i;
        string s = to_string(sq);
        if ((int) s.size() < 2) {
            continue;
        }

        bool ok = false;
        for (int p = 1; p < (int) s.size(); ++p) {
            string leftStr = s.substr(0, p);
            string rightStr = s.substr(p);

            // 检查左右两段是否有非法前导零。
            if ((int) leftStr.size() > 1 && leftStr[0] == '0') {
                continue;
            }
            if ((int) rightStr.size() > 1 && rightStr[0] == '0') {
                continue;
            }

            int left = stoi(leftStr);
            int right = stoi(rightStr);
            if (isSquare(left) && isSquare(right)) {
                ok = true;
                break;
            }
        }

        if (ok) {
            good.push_back(sq);
        }
    }
    return good;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    vector good = buildGoodNumbers()

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

互联网刷题笔试宝典 文章被收录于专栏

互联网刷题笔试宝典,这里涵盖了市面上大部分的笔试题合集,希望助大家春秋招一臂之力

全部评论

相关推荐

03-25 17:03
门头沟学院 Java
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

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