常用算法代码模板与题单 | A - 基础算法

【高精度】

算法模板

高精度加法

// 结构体
struct BIG
{
    int len, num[1005];
    BIG()  // 构造函数,初始化高精度数
    {
        memset(num, 0, sizeof(num));
        len = 1;
    }
    void set(int n)  // 整数转高精度
    {
        memset(num, 0, sizeof(num));
        len = 0;
        while (n > 0)
        {
            num[++len] = n % 10;
            n /= 10;
        }
        if (len == 0)
        {
            len = 1;
        }
    }
    void set(string s)  // 字符串转高精度
    {
        memset(num, 0, sizeof(num));
        len = s.size();
        for (int i = 1; i <= len; i++)
        {
            num[i] = s[len - i] - '0';
        }
    }
    void print()  // 输出高精度数
    {
        for (int i = len; i >= 1; i--)
        {
            cout << num[i];
        }
        cout << endl;
    }
};
// 加法
BIG operator+(BIG a, BIG b)  // 重载加法运算符
{
    BIG c;                          // 存储结果的变量
    c.len = max(a.len, b.len);      // 结果的初始长度为较大数的长度
    int u = 0;                      // 进位值,初始为0

    for (int i = 1; i <= c.len; i++)  // 从低位到高位逐位相加
    {
        int t = a.num[i] + b.num[i] + u;  // 当前位的和
        c.num[i] = t % 10;                // 取个位作为当前位结果
        u = t / 10;                       // 计算进位
    }

    if (u > 0)                      // 如果最后还有进位
        c.num[++c.len] = u;         // 增加一位存储进位

    return c;                       // 返回相加结果
}

高精度减法

// 高精度比较
bool operator<(BIG a, BIG b)  // 小于比较
{
    if (a.len != b.len)
    {
        return a.len < b.len;
    }
    for (int i = a.len; i >= 1; i--)
    {
        if (a.num[i] != b.num[i])
        {
            return a.num[i] < b.num[i];
        }
    }
    return false;
}
// 减法
BIG operator - (BIG a, BIG b)  // 高精度减法(假设a >= b)
{
    BIG c;
    c.len = max(a.len, b.len);
    int u = 0;  // 借位
    for (int i = 1; i <= c.len; i++)
    {
        int t = a.num[i] - b.num[i] - u;
        if (t < 0)
        {
            c.num[i] = t + 10;
            u = 1;
        }
        else
        {
            c.num[i] = t;
            u = 0;
        }
    }
    while (c.num[c.len] == 0 && c.len > 1)  // 去除前导零
    {
        c.len--;
    }
    return c;
}

高精度乘法

// 乘法
BIG operator*(BIG a, int b)  // 高精度乘以整数
{
    BIG c;
    c.len = a.len;
    int u = 0;  // 进位
    for (int i = 1; i <= c.len; i++)
    {
        int t = a.num[i] * b + u;
        c.num[i] = t % 10;
        u = t / 10;
    }
    while (u > 0)  // 处理最后的进位
    {
        c.num[++c.len] = u % 10;
        u /= 10;
    }
    return c;
}

高精度除法

BIG operator/(BIG a, int b)  // 高精度除以整数(整除)
{
    BIG c;
    c.len = a.len;
    int r = 0;  // 记录余数
    for (int i = c.len; i >= 1; i--)  // 从最高位开始除
    {
        int t = r * 10 + a.num[i];
        c.num[i] = t / b;
        r = t % b;
    }
    while (c.num[c.len] == 0 && c.len > 1)  // 去除前导零
    {
        c.len--;
    }
    return c;
}

高精度求余

int mod(BIG a, int div)
{
    long long rem = 0; // 余数
    for (int i = a.len; i >= 1; i--) // 从高位到低位
        rem = (rem * 10 + a.num[i]) % div; // 模拟除法
    return (int)rem;
}
//如果rem为0说明是s是div的倍数

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 791 高精度加法 xxxxxx
AcWing 792 高精度减法
AcWing 793 高精度乘法
AcWing 794 高精度除法
AcWing 3427 大整数的因子
AcWing 5508 回文数
AcWing 5900 高精度乘法
AcWing 5901 高精除
AcWing 5902 大整数加法
AcWing 5903 大整数减法
AcWing 5904 计算2的N次方
AcWing 5905 求10000以内n的阶乘
AcWing 5906 阶乘和
AcWing 5907 大整数乘法
AcWing 5908 除以13
AcWing 5959 2011
洛谷 P1015 回文数 普及-
洛谷 P1255 数楼梯 普及-
洛谷 P1303 A B Problem 普及-
洛谷 P1480 AB Problem 普及-
洛谷 P1601 A+B Problem(高精) 普及-
洛谷 P2142 高精度减法 普及-
洛谷 P2437 蜜蜂路线 普及-
洛谷 B4380 红蓝扑克排列 普及
洛谷 P1045 麦森数 普及
洛谷 P1096 Hanoi 双塔问题 普及
洛谷 P1249 最大乘积 普及
洛谷 [[P2005 AB Problem II]] 普及
洛谷 P1050 循环 提高+
学而思编程 简单除法问题 普及进阶 ⭐⭐⭐ 高精度除法 + 大数取模 实现高精度整数结构体 BIG,支持高精度除以整数的除法(从高位到低位逐位计算商和余数),先计算 ⌊n/m⌋ 的商,再将商转换为字符串后逐位取模 \(10007\) 得到最终答案,时间复杂度 \(O(L)\)\(L\)\(n\) 的位数,\(L \le 10^6\))。

【整数二分】

算法模板

二分查找

lower_bound(a+1, a+n+1, x);  // 第一个 >= x 的位置
upper_bound(a+1, a+n+1, x);  // 第一个 > x 的位置
upper_bound(a+1, a+n+1, x) - 1;  // 最后一个 <= x 的位置
upper_bound(a+1, a+n+1, x) - lower_bound(a+1, a+n+1, x);  // 等于x的个数

二分答案

// [l,r]区间寻找最小的最大值
int l = 0, r = 1e18;
while (l < r)
{
    int mid = l + r >> 1;
    if (check(mid)) r = mid;    // check()判断mid是否满足性质
    else l = mid + 1;
}
// l就是答案

// [l, r]区间寻找最大的最小值
while (l < r)
{
    int mid = l + r + 1 >> 1;  //当l=mid时,一定要l+r+1
    if (check(mid)) l = mid;
    else r = mid - 1;
}
// l就是答案

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 503 借教室
AcWing 789 数的范围 简单 ⭐⭐ 整数二分查找(两次二分) 在升序数组中两次二分查找目标元素的左右边界:第一次找左边界(第一个 \(\ge x\) 的位置),mid = (l+r)>>1,若 q[mid] >= xr = mid,否则 l = mid+1;若 q[l] != x 则输出 -1 -1;第二次找右边界(最后一个 \(\le x\) 的位置),mid = (l+r+1)>>1(注意 \(+1\) 防止死循环),若 q[mid] <= xl = mid,否则 r = mid-1;每次查询时间复杂度 \(O(\log n)\)
AcWing 1227 分巧克力
AcWing [[4927 河流跳房子]]
AcWing 5963 查找最接近的元素
AcWing 5965 网线主管
AcWing 5966 月度开销
AcWing 5967 和为给定数
洛谷 AT_abc443_b Setsubun 入门
洛谷 AT_abc334_d Reindeer and Sleigh 普及-
洛谷 AT_abc355_c Bingo 2 普及-
洛谷 AT_abc358_d Souvenirs 普及-
洛谷 AT_abc365_c Transportation Expenses 普及-
洛谷 AT_abc376_c Prepare Another Box 普及-
洛谷 AT_abc382_c Kaiten Sushi 普及-
洛谷 AT_abc388_c Various Kagamimochi 普及-
洛谷 AT_abc463_c Tallest at the Moment 普及-
洛谷 CF670C Cinema 普及-
洛谷 P1102 A-B数对 普及-
洛谷 P1678 烦恼的高考志愿 普及-
洛谷 [[P1824 Aggressive cows]] 普及-
洛谷 P1873 砍树 普及-
洛谷 P2249 查找 普及-
洛谷 P2969 Music Notes 普及-
洛谷 [[P9937 Acowdemia I]] 普及-
洛谷 U218625 网线主管 普及-
洛谷 AT_abc319_d Minimum Width 普及
洛谷 AT_abc360_d Ghost Ants 普及
洛谷 AT_abc415_e Hungry Takahashi 普及
洛谷 AT_abc463_d Maximize the Gap 普及 ⭐⭐⭐ 二分答案 + 贪心判定 按右端点升序排序后,二分答案范围为 \([0, 10^9]\),判定函数 check(mid) 贪心选择右端点最小的布作为起点,遍历后续布:若当前布左端点与上一块选中布右端点的距离 \(\geq mid\) 则选中该布并更新 last 为当前右端点;若最终选出不少于 \(K\) 块布则 mid 可行;二分取上中点 mid = (l+r+1)/2 防死循环,若 check(mid) 为真则 l=mid 尝试更大值,否则 r=mid-1;最终若 l=0 输出 \(-1\),否则输出 \(l\),时间复杂度 \(O(N \log N + N \log MAX)\)
洛谷 [[B4107 刷题]] 普及
洛谷 P1083 借教室 普及
洛谷 P1111 修复公路 普及
洛谷 P1182 数列分段 普及
洛谷 P1281 书的复制 普及
洛谷 P1902 刺杀大使 普及
洛谷 P2440 木材加工 普及
洛谷 P2678 跳石头 普及
洛谷 P3743 kotori的设备 普及
洛谷 P3853 路标设置 普及
洛谷 P9125 Cow-libi 普及
洛谷 [[P9948 Race]] 普及
洛谷 [[P10719 黑白格]] 普及
洛谷 P13013 奖品兑换 普及 ⭐⭐⭐ 整数二分 + 贪心调整 设兑换 \(mid\) 份奖品,每份需 \(a\) 张券1和 \(b\) 张券2(或互换),二分答案后用贪心调整:若券1不足则将部分"券1为主"的方案换成"券2为主"(每次调整节省 \(a-b\) 张券1、多花 \(a-b\) 张券2),检查调整后两种券均不超限制,时间复杂度 \(O(\log \min(n,m))\),空间复杂度 \(O(1)\)
洛谷 P14917 数字移动 普及
洛谷 AT_abc385_d Santa Claus 2 普及+
洛谷 AT_abc417_d Takahashi's Expectation 普及+
洛谷 P1314 聪明的质监员 普及+
洛谷 [[P3611 Cow Dance Show]] 普及+
洛谷 [[P6004 Wormhole Sort]] 普及+
洛谷 P9124 Bakery 普及+
洛谷 AT_abc389_e Square Price 提高+
洛谷 P4090 Greedy Gift Takers 提高+
洛谷 P10451 Innovative Business 提高+
AtCoder AT_awc0005_d Splitting Delivery Packages ⭐⭐⭐ 二分答案 + 贪心判定 二分答案范围为 \([0, \sum A_i]\),判定函数 check(x) 贪心地将数组从左到右分割:维护当前段和 sum,若 sum + a[i] >= x 则段数 ans++ 并重置 sum=0(尽可能早结束当前段),否则 sum += a[i];若最终 ans >= Kx 可行;二分取 mid = (l+r+1)/2 防死循环,若 check(mid) 为真则 l=mid 尝试更大值,否则 r=mid-1;最终 l 即为最大可行最小载重,时间复杂度 \(O(N \log S)\)
AtCoder AT_awc0027_c Building a Wireless Network
AtCoder AT_awc0032_c Observatory with a Mountain View
AtCoder AT_awc0035_b Package Distribution Center
AtCoder AT_awc0036_c Splitting Logs
AtCoder AT_awc0046_b Organizing the Locker
AtCoder AT_awc0046_d Operation Plan for Distribution Center ⭐⭐⭐ 排序 + 前缀和 + 枚举端点 + 二分定位 将期望日期排序并求前缀和后,枚举每个 \(D_i\) 作为区间左端点(\(l=D_i, r=l+K-1\))或右端点(\(r=D_i, l=r-K+1\)),用 lower_bound / upper_bound 二分定位区间内元素范围,左侧代价为 \((left-1)\cdot l - sd[left-1]\),右侧代价为 \((sd[n]-sd[right])-(n-right)\cdot r\),取所有情况最小值,时间复杂度 \(O(N \log N)\)
AtCoder AT_awc0080_b Quality Inspection and Product Disposal ⭐⭐ 排序 + 二分查找 + 双指针 将质量分数升序排序后,用指针 \(st\) 维护当前已处理到的位置,每次查询用 upper_bound 找到第一个 \(\geq T_j\) 的位置 \(pos\),若 \(pos \leq st\) 则新销毁数为 \(0\),否则为 \(pos-st\),随后更新 \(st = \max(st, pos)\),时间复杂度 \(O(N \log N + Q \log N)\)
AtCoder AT_awc0082_d Corridor Doors and Hit Points ⭐⭐⭐⭐ 二分答案 + 等差数列计数 + 前缀和 对每种安全模式用等差数列公式 \(O(1)\) 计算时刻 \(t\) 时门 \(x\) 的锁数量(首项 \(first = ((r \bmod a) + (v \bmod a) \cdot (t \bmod a)) \bmod a\),修正为 \(a\) 若余数为 \(0\),则 \(\leq idx\) 的锁数为 \(\lfloor\frac{idx-first}{a}\rfloor+1\)),对每个查询分别向左右二分:向左在 \([0,S_j]\) 找最远边界使区间锁数 \(\leq P_j\)(下取整中点),向右在 \([S_j,L-1]\) 同理(上取整中点防死循环),最终答案为左扩房间数 + 右扩房间数 \(-1\),时间复杂度 \(O(Q \cdot N \cdot \log L)\)
AtCoder AT_awc0098_b Library Book Lending
AtCoder AT_awc0101_b A Single Strike of Dominoes ⭐⭐⭐ 整数二分 + 模拟验证 对施加的力 \(X\) 进行二分搜索(范围 \([1, 10^9]\)),每次用 check(x) 模拟:先将所有柱子耐久度减去 \(X\),然后从左到右遍历,若第 \(i\) 根柱子倒塌(耐久度 \(\le 0\))则第 \(i+1\) 根额外减 \(1\),最后判断是否全部倒塌,根据 check 结果调整二分边界,时间复杂度 \(O(N \log A_{\max})\),空间复杂度 \(O(N)\)
学而思编程 买整数 普及进阶 ⭐⭐ 整数二分 对能购买的最大整数进行整数二分,验证函数 check(x) 计算数字 \(x\) 的位数后判断 a*x + b*位数 <= k 是否成立,利用价格关于 \(x\) 的单调性二分查找满足条件的最大 \(x\),边界为 \([0, 10^9]\),时间复杂度 \(O(\log(10^9) \cdot \log x)\)(每次 check\(O(\log x)\) 计算位数)。
学而思编程 射击王 普及进阶 ⭐⭐⭐⭐ 整数二分 + 贪心排序 对最终得分 \(mid\) 进行整数二分,check(mid) 计算每个气球在得分不超过 \(mid\) 的前提下最晚可射击时间 t[i] = (mid - h[i]) / s[i],将所有 t[i] 升序排序后贪心验证:第 \(i\) 个气球必须在时间 \(i-1\) 之前射击(从第 0 秒开始),即需满足 \(t[i] \ge i-1\),二分查找满足条件的最小 \(mid\),时间复杂度 \(O(n \log n \cdot \log(\max \text{ans}))\)\(n \le 10^5\))。
学而思编程 展览会 普及进阶 ⭐⭐⭐⭐ 整数二分 + 贪心验证 对"华丽度"(选出画中最低价值)进行整数二分,验证函数 check(mid) 按位置排序后从左到右贪心选择:若当前画价值 \(\ge mid\) 且与上一幅选中画的距离 \(\ge D\) 则选中,最终判断是否能选出至少 \(m\) 幅画,二分查找最大的可行华丽度,时间复杂度 \(O(n \log n + n \log V)\)\(n \le 10^5, V\) 为最大价值)。
学而思编程 折半与最小值 普及进阶 ⭐⭐⭐⭐ 整数二分 + 贪心验证 对答案 \(x\) 进行整数二分,验证函数 check(x) 贪心计算每根木棒 \(a_i\) 不断二分后能得到的最少片段数(当片段长度 \(\ge x\) 时停止分割),若总片段数 \(\ge n+m\)\(x\) 可行,二分查找最大的可行 \(x\),时间复杂度 \(O(T \cdot n \cdot \log(\max a_i) \cdot \log a_i)\)\(T\) 为测试用例数,\(n \le 10^5, a_i \le 10^9\))。

【浮点二分】

算法模板

double l = 0, r = 1000;
double eps = 1e-6;   // eps 表示精度,取决于题目对精度的要求,需要比预留的小数位+2
while (r - l > eps)
{
    double mid = (l + r) / 2;
    if (check(mid)) r = mid;
    else l = mid;
}
return l;

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 790 数的三次方根 简单 浮点二分 在区间 \([-10000, 10000]\) 上进行浮点二分,每次取中点 \(mid\) 判断 \(mid^3 \geq x\) 是否成立以缩小区间,当区间长度 \(< 10^{-8}\) 时停止并输出左端点(保留6位小数),时间复杂度 \(O(\log(\frac{20000}{\epsilon}))\)
AcWing 5499 一元三次方程求解
AcWing 5964 二分法求函数的零点
AcWing 5975 膨胀的木棍
洛谷 P1024 一元三次方程求解 普及-
洛谷 P1163 银行贷款 普及
洛谷 P1570 KC喝咖啡 普及
洛谷 [[P10450 Best Cow Fences]] 普及
洛谷 [[P4047 部落划分]] 普及+

【三分】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 AT_abc426_e Closest Moment 普及+

【前缀和】

算法模板

一维前缀和

// 前缀和求解
for (int i=1; i<=n; i++)
    s[i] = s[i-1] + a[i];
printf("%d\n", s[r]-s[l-1]);

二维前缀和

//预处理s[i,j]
for (int i=1; i<=n; i++)
    for (int j=1; j<=m; j++)
        s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];

//询问
while (q--) {
    int x1, y1, x2, y2;
    scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    printf("%d\n", s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 464 推销员
AcWing 795 前缀和 简单 一维前缀和 预处理前缀和数组 \(s[i] = s[i-1] + a[i]\),每次查询区间 \([l,r]\) 的和直接由 \(s[r] - s[l-1]\)\(O(1)\) 时间内得出,时间复杂度 \(O(n + m)\)
AcWing 796 子矩阵的和 简单 二维前缀和 预处理二维前缀和数组 \(s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j]\),每次查询子矩阵和直接由容斥原理 \(O(1)\) 得出:\(s[x_2][y_2] - s[x_2][y_1-1] - s[x_1-1][y_2] + s[x_1-1][y_1-1]\),时间复杂度 \(O(nm + q)\)
AcWing 1827 水壶
AcWing 3347 菊花链
洛谷 AT_abc331_c Sum of Numbers Greater Than Me 普及-
洛谷 AT_abc337_d Cheating Gomoku Narabe 普及-
洛谷 AT_abc339_c Perfect Bus 普及-
洛谷 AT_abc389_c Snake Queue 普及-
洛谷 AT_abc397_c Variety Split Easy 普及-
洛谷 AT_abc401_c K-bonacci 普及-
洛谷 AT_abc405_c Sum of Product 普及-
洛谷 AT_abc418_c Flush 普及-
洛谷 AT_abc425_c Rotate and Sum Query 普及-
洛谷 B3612 求区间和 普及-
洛谷 B4005 黑白方块 普及-
洛谷 B4038 平衡序列 普及-
洛谷 [[B4105 消灭怪兽]] 普及-
洛谷 B4192 分数线 普及-
洛谷 B4303 字母移位 普及-
洛谷 [[B4415 排兵布阵]] 普及-
洛谷 P1719 最大加权矩形 普及-
洛谷 [[P3131 Subsequences Summing to Sevens]] 普及-
洛谷 P8218 求区间和 普及-
洛谷 [[P10189 Maximizing Productivity]] 普及-
洛谷 P17010 排排坐 普及- ⭐⭐ 贪心排序 + 前缀和 将数字按降序排列使大数尽量靠左(位置 \(i\) 贡献 \(a_i \times (n-i+1)\) 次),排序后累加前缀和 sa[i] 得总糖果量,时间复杂度 \(O(n \log n)\),空间复杂度 \(O(n)\)
洛谷 AT_abc393_d Swap to Gather 普及
洛谷 AT_abc398_d Bonfire 普及
洛谷 AT_abc418_d XNOR Operation 普及
洛谷 AT_abc423_e Sum of Subarrays 普及
洛谷 AT_abc426_d Pop and Insert 普及
洛谷 AT_abc438_d Tail of Snake 普及
洛谷 AT_abc440_c Striped Horse 普及
洛谷 AT_abc461_d Count Subgrid Sum = K 普及 ⭐⭐⭐ 列前缀和 + 枚举上下边界降维 + 哈希表 预处理列前缀和 \(colSum[j][i]\) 后,枚举上下边界 \([r_1,r_2]\) 将二维问题降维为一维:计算每列在行区间内的和 \(colVal_j = colSum[j][r_2] - colSum[j][r_1-1]\),再用哈希表维护横向前缀和频率,遍历列时查询 \(sum-K\) 的出现次数并累加答案,时间复杂度 \(O(H^2 \cdot W)\)
洛谷 [[P1369 矩形]] 普及
洛谷 P2280 激光炸弹 普及
洛谷 P2822 组合数问题 普及
洛谷 P3406 海底高铁 普及
洛谷 P5686 和积和 普及
洛谷 [[P9426 抓娃娃]] 普及
洛谷 P14074 有趣的数字和 普及
洛谷 P2119 魔法阵 普及+
洛谷 P2671 求和 普及+
洛谷 P8865 种花 普及+
洛谷 P9236 异或和之和 普及+
洛谷 [[P10724 区间乘积]] 普及+
洛谷 [[AT_abc468_e Sum of Average]]
AtCoder AT_awc0003_d Consecutive Practice Days
AtCoder AT_awc0004_e Sum of Intervals ⭐⭐ 前缀和 + 哈希表 初始化哈希表 mp[0] = 1,遍历数组时维护前缀和 \(sa[i]\),每次查询哈希表中 \(sa[i]-K\) 的出现次数并累加答案(即存在多少个位置 \(j\) 使得子数组 \([j+1,i]\) 的和为 \(K\)),随后将当前前缀和加入哈希表,时间复杂度 \(O(N \log N)\)
AtCoder AT_awc0008_c Anomaly Detection in Sensor Data
AtCoder AT_awc0013_d Distance Between Cities ⭐⭐⭐ 维度分解 + 排序 + 前缀和 利用曼哈顿距离的维度独立性将 \(M\) 维问题分解为 \(M\) 个一维问题,对每个维度的坐标升序排序后计算前缀和,第 \(i\) 个元素对总距离的贡献为 \(B_i \cdot (i-1) - sa[i-1]\)(即与前面所有元素的差之和),累加所有维度贡献得最终答案,时间复杂度 \(O(M \cdot N \log N)\)
AtCoder AT_awc0014_b Marathon
AtCoder AT_awc0017_c Same Color Check in the Flower Bed
AtCoder AT_awc0022_c Road Pothole Survey
AtCoder AT_awc0023_c Factory Tour
AtCoder AT_awc0044_b Library Book Survey on the Bookshelf
AtCoder AT_awc0048_d Maximum Score ⭐⭐ 二维前缀和 + 因数枚举 预处理二维前缀和数组 \(sa[i][j]\) 后,枚举 \(K\) 的所有约数对 \((h,w)\)(其中 \(h \leq N, w \leq M\)),对每个合法尺寸用 \(O(1)\) 的容斥公式 getsum(r1,c1,r2,c2) = sa[r2][c2] - sa[r1-1][c2] - sa[r2][c1-1] + sa[r1-1][c1-1] 枚举所有子矩阵位置并更新最大值,若不存在合法矩形则输出 \(-1\),时间复杂度 \(O(NM + d(K) \cdot NM)\)
学而思编程 构建回文(二) 普及奠基 ⭐⭐⭐ 前缀和 区间能重排成回文当且仅当该区间内出现奇数次的字母个数 \(\le 1\),用 \(26\) 维前缀和统计每个区间的字母频次。
学而思编程 国庆旅行 普及奠基 ⭐⭐⭐ 前缀最值 / 双指针优化 将目标式 \(a[i]+a[j]-(j-i)\) 变形为 \((a[i]+i) + (a[j]-j)\),固定 \(i\) 时需要找 \(j>i\)\((a[j]-j)\) 的最大值,预处理后缀最大值数组 \(s[i] = \max_{k \ge i}(a[k]-k)\),然后枚举 \(i\)\(1\)\(n\),计算 \(a[i]+i+s[i+1]\) 取最大值,时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)
学而思编程 阶梯求和 普及奠基 ⭐⭐ 前缀和 预处理普通前缀和 \(\text{sum1}[i]\) 与加权前缀和 \(\text{sum2}[i]\),查询时公式转化为 \(\text{sum2}[r]-\text{sum2}[l-1]-(l-1)\times(\text{sum1}[r]-\text{sum1}[l-1])\)
学而思编程 懒惰的牛 普及奠基 ⭐⭐ 前缀和 / 滑动窗口 将草地按坐标离散化后前缀和,枚举每个位置作为中心,计算覆盖范围 \([i-k, i+k]\) 内的青草总量取最大值。
学而思编程 平衡点 普及奠基 ⭐⭐⭐ 前缀和 预处理前缀和与后缀和,再分别累加得到左右引力 \(L[k]\)\(R[k]\),枚举 \(k\) 求 $\
学而思编程 子矩阵的和 普及奠基 ⭐⭐⭐ 前缀和 + 容斥原理 预处理每行的行前缀和,查询时用 area() 函数通过行前缀和快速计算矩形区域和(遍历行累加每行的区间和);对于两个正方形区域的并集,用容斥原理:\(ans = sum_1 + sum_2 - sum_{交集}\),其中交集通过坐标排序后取中间两个坐标确定,若两矩形不相交则无需减去,单次查询时间复杂度 \(O(n)\)(行数),预处理 \(O(n \times m)\),空间复杂度 \(O(n \times m)\)

【树上前缀和】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 P4427 求和 普及+

【差分】

算法模板

一维差分

// 获得差分数组
for (int i=1; i<=n; i++) b[i] = a[i]-a[i-1];
// for (int i=1; i<=n; i++) insert(i, i, a[i]);

// 给区间[l, r]中的每个数加上c:
void insert(int l, int r, int c)
{
    b[l]+=c;
    b[r+1]-=c;
}

// 还原差分数组为原数组
for (int i=1; i<=n; i++) b[i] += b[i-1];

二维差分

//预处理出b[i][j]差分数组
for (int i=1; i<=n; i++)
    for (int j=1; j<=m; j++)
        insert(i, j, i, j, a[i][j]);

// 给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
void insert(int x1, int y1, int x2, int y2, int c)
{
    b[x1][y1] += c;
    b[x2+1][y1] -= c;
    b[x1][y2+1] -= c;
    b[x2+1][y2+1] += c;
}

//通过前缀和还原数组
for (int i=1; i<=n; i++)
    for (int j=1; j<=m; j++)
        b[i][j] += b[i-1][j] + b[i][j-1] - b[i-1][j-1];

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 797 差分 简单 一维差分 构建差分数组 \(b[i] = a[i] - a[i-1]\),每次区间 \([l,r]\)\(c\) 的操作转化为 \(b[l] += c\)\(b[r+1] -= c\),最后对差分数组求前缀和 \(b[i] += b[i-1]\) 即得更新后的序列,时间复杂度 \(O(n + m)\)
AcWing 798 差分矩阵 简单 ⭐⭐ 二维差分 构建二维差分数组,子矩阵 \((x_1,y_1)\)\((x_2,y_2)\)\(c\) 的操作转化为四角更新 \(b[x_1][y_1] += c\)\(b[x_2+1][y_1] -= c\)\(b[x_1][y_2+1] -= c\)\(b[x_2+1][y_2+1] += c\),最后对差分数组求二维前缀和 \(b[i][j] += b[i-1][j] + b[i][j-1] - b[i-1][j-1]\) 即得最终矩阵,时间复杂度 \(O(nm + q)\)
AcWing 4401 找回数组
洛谷 AT_abc408_c Not All Covered 普及-
洛谷 P2367 语文成绩 普及-
洛谷 P3397 地毯 普及-
洛谷 P11853 植树节 普及-
洛谷 AT_abc388_d Coming of Age Celebration 普及
洛谷 AT_abc419_d Substr Swap 普及
洛谷 [[P1672 Feed Accounting]] 普及
洛谷 [[P2879 Tallest Cow]] 普及
洛谷 [[P10133 Balancing Bacteria]] 普及
洛谷 P4552 IncDec Sequence 普及+
洛谷 [[P11790 焚风现象]] 普及+
洛谷 [[AT_abc468_b Corridor Watch]]
AtCoder AT_awc0022_d Simultaneous Control of Light Bulb Panels ⭐⭐⭐ 差分 + 贪心 用差分数组维护翻转操作的累积影响(模 \(2\)),从左到右贪心遍历:若当前位置经累积翻转后仍为灭(\(a[i] \oplus diff[i] = 1\)),则在位置 \(i\) 开始翻转连续 \(K\) 个灯泡(\(diff[i] \oplus= 1\)\(diff[i+K] \oplus= 1\)),若剩余长度不足 \(K\) 则无解输出 \(-1\),时间复杂度 \(O(N)\)
AtCoder AT_awc0024_d Highlighting with a Fluorescent Pen
AtCoder AT_awc0026_d Repainted Wall ⭐⭐⭐ 扫描线 + 差分 对每个区间 \([L_i, R_i]\) 在端点处做差分标记(起点+1、终点-1),用 map 按坐标排序后扫描线遍历,维护当前覆盖次数 cnt,若 cnt >= K 则将区间 \([last, pos)\) 的长度累加进答案,时间复杂度 \(O(N \log N)\)
AtCoder AT_awc0034_c Watering the Flower Bed ⭐⭐⭐ 差分 + 贪心 用差分数组 imos 维护区间加法的累积影响,从左到右贪心遍历:若当前花坛经累积增加后仍不足目标值 \(T\)\(a[i] + cur < T\)),则在位置 \(i\) 执行 \(need = T - (a[i] + cur)\) 次操作(\(ans += need\)),并通过 imos[i+K] -= need\(K\) 个位置后自动消除影响,最后输出总花费 \(ans \times C\),时间复杂度 \(O(N)\)
AtCoder AT_awc0044_c Range Addition 一维差分 + 前缀和 用差分数组离线处理 \(M\) 个区间加 \(1\) 操作(\(a[L_i]++\)\(a[R_i+1]--\)),最后对数组求前缀和 \(a[i] = a[i-1] + a[i]\) 即得每个位置的最终值,时间复杂度 \(O(N + M)\)
AtCoder AT_awc0045_c Watering Duty 一维差分 + 前缀和 用差分数组离线处理 \(Q\) 个区间加操作(\(a[L_i] += C_i\)\(a[R_i+1] -= C_i\)),最后对数组求前缀和 \(a[i] += a[i-1]\) 即得每个种植箱的总水量,时间复杂度 \(O(N + Q)\)
AtCoder AT_awc0048_c Streetlights and Blizzard ⭐⭐ 一维差分 + 前缀和 用差分数组离线处理 \(M\) 个区间减操作(\(a[L_j] -= D_j\)\(a[R_j+1] += D_j\)),求前缀和还原每个位置的总减少量后,统计满足 \(H_i + a[i] \geq 1\) 的路灯数量,时间复杂度 \(O(N + M)\)
AtCoder AT_awc0088_c Farm Harvest Festival

【树上差分】

算法模板

void dfs2(int u, int f)
{
    for (int i=0; i<h[u].size(); i++)
    {
        int j = h[u][i];
        if (j==f) continue;
        dfs2(j, u);
        power[u] += power[j];
    }
}

for (int i=1; i<=a; i++)
{
    int x, y;
    cin >> x >> y;
    int l = lca(x, y);
    ++power[x]; ++power[y];
    --power[l]; --power[fa[l][0]];
}
dfs2(1, 0);

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 352 闇の連鎖 困难 ⭐⭐⭐⭐⭐ 树上差分 + LCA(倍增) \(N-1\) 条主要边构建树并预处理倍增数组求LCA后,对每条附加边 \((u,v)\) 执行树上差分(\(d[u]++\)\(d[v]++\)\(d[lca]-=2\)),再通过DFS后序遍历累加子树差分值得到每条主要边被覆盖的次数 \(s\):若 \(s=0\) 则贡献 \(M\) 种方案(需切断任意附加边),若 \(s=1\) 则贡献 \(1\) 种方案(需切断对应那条附加边),若 \(s \geq 2\) 则贡献 \(0\) 种方案,累加所有方案数得答案,时间复杂度 \(O((N+M) \log N)\)
洛谷 P3128 Max Flow 普及+ ⭐⭐⭐⭐ 树上差分 + LCA(倍增) 预处理树的深度和倍增数组求LCA后,对每条路径 \((s,t)\) 执行树上差分:\(power[s]++\)\(power[t]++\)\(power[lca]--\)\(power[fa[lca][0]]--\),最后通过一次DFS将子节点的权值累加到父节点,统计每个隔间的压力并取最大值,时间复杂度 \(O((N+K) \log N)\)

【ST表】

算法模板

// 预处理ST表
for (int j = 1; j <= 20; j++)          // 枚举区间长度(2^j)
    for (int i = 1; i + (1 << j) - 1 <= n; i++)  // 枚举区间起点
    {
        // 状态转移:合并左右两个子区间
        f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    }
}

// 处理查询
for (int i = 1; i <= m; i++)
{
    int l, r;
    scanf("%d%d", &l, &r);  // 输入查询区间
    // 计算区间长度的对数
    int k = log2(r - l + 1);
    // 查询区间最大值:取两个覆盖区间的最大值
    printf("%d\n", max(f[l][k], f[r - (1 << k) + 1][k]));
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 [[P2880 Balanced Lineup]] 普及
洛谷 P3865 ST表 & RMQ问题 普及 ⭐⭐ ST表(稀疏表) 预处理 \(f[i][j]\) 表示区间 \([i, i+2^j-1]\) 的最大值,状态转移 \(f[i][j] = \max(f[i][j-1], f[i+2^{j-1}][j-1])\),查询时取 \(k = \lfloor\log_2(r-l+1)\rfloor\),答案为 \(\max(f[l][k], f[r-2^k+1][k])\),预处理 \(O(N \log N)\),单次查询 \(O(1)\)
洛谷 P7333 JFCA 普及+
洛谷 P8818 策略游戏 普及+
洛谷 P10059 Choose 普及+

【快速排序】

算法模板

void qsort(int l, int r)
{  // 对区间[l, r]进行快速排序
    int x = a[(l+r)/2], i=l, j = r;  // 选择中间的元素作为基准值
    while (i<=j)
    {
        while (a[i]<x) i++;  // 在x左边从左到右找到第一个>=x的数字a[i]
        while (a[j]>x) j--;  // 在x右边从右到左找到第一个<=x的数字a[j]
        // 如果找到的两个元素的下标没有交错,交换这两个元素,并移动下标
        if (i<=j) swap(a[i], a[j]), i++, j--;
    }
    if (l<j) qsort(l, j);  // 递归地对左半部分进行快速排序
    if (i<r) qsort(i, r);  // 递归地对右半部分进行快速排序
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 490 统计数字
AcWing 785 快速排序 简单 ⭐⭐ 快速排序(随机化基准) 随机选择基准元素避免最坏情况,用双指针 \(i\)(从左找 \(\geq x\))和 \(j\)(从右找 \(\leq x\))进行分区,相遇后递归排序左右子区间,平均时间复杂度 \(O(n \log n)\),最坏 \(O(n^2)\)
AcWing 786 第k个数
AcWing 4653 数位排序
洛谷 AT_abc027_a 長方形 入门
洛谷 AT_abc058_a ι⊥l 入门
洛谷 AT_abc066_a ringring 入门
洛谷 P1177 排序 普及-
洛谷 P1923 求第k小的数 普及-

【归并排序】

算法模板

void merge_sort(int l, int r)
{
    if (l==r) return;  // 如果子数组只有一个元素,则不需要排序,直接返回
    int mid = (l + r) / 2 ;
    merge_sort(l, mid);  // 递归地对左半部分进行归并排序
    merge_sort(mid+1, r);  // 递归地对右半部分进行归并排序

    int x = l, y = mid+1, cnt = l-1;
    while (x<=mid && y<=r)  // 只要左右两端子数组都不为空
    {
        if (a[x]<=a[y])  // 将两段子数组左端点较小者插入b数组
        {
            b[++cnt] = a[x];
            x++;
        }
        else
        {
            b[++cnt] = a[y];
            y++;
        }
    }
    // 合并过程中其中一个子数组的元素已全部合并完成,而另一个子数组仍有剩余元素的情况
    for (int i=x; i<=mid; i++) b[++cnt] = a[i];  // 如果左半部分还有剩余的元素,将它们复制到b中
    for (int i=y; i<=r; i++) b[++cnt] = a[i];  // 如果右半部分还有剩余的元素,将它们复制到b中

    for (int i=l; i<=r; i++) a[i] = b[i];  // 将b中已经排序好的部分复制回a中,完成合并
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 787 归并排序 简单 ⭐⭐ 归并排序(分治 + 双指针合并) 递归将数组二分至单元素区间,然后用双指针合并两个有序子数组(取较小者放入临时数组,处理剩余元素后拷贝回原数组),时间复杂度严格 \(O(n \log n)\),空间复杂度 \(O(n)\)
AcWing 788 逆序对的数量
AcWing 5910 求逆序对
AcWing 5958 光荣的梦想
AcWing 5960 输出前k大的数
AcWing 5962 求排列的逆序数
洛谷 P1908 逆序对 普及- ⭐⭐⭐ 归并排序 / 离散化 + 树状数组 方法一(归并排序):分治过程中合并两个有序子数组时,若右半部分元素 \(a[j]\) 小于左半部分元素 \(a[i]\),则左半部分从 \(i\)\(mid\) 的所有元素都与 \(a[j]\) 构成逆序对,累加 \(mid-i+1\) 到答案,时间复杂度 \(O(n \log n)\);方法二(树状数组):将数值离散化后,从左到右遍历,用树状数组维护已出现元素频率,每次查询已出现且比当前大的元素数量(\(query(n)-query(newval)\))即为以当前元素结尾的逆序对数,时间复杂度 \(O(n \log n)\)
洛谷 P1966 火柴排队 普及+

【堆排序】

算法模板

基本声明方式

// 整型大根堆
priority_queue<int, vector<int> > pq;
// 整型小根堆
priority_queue<int, vector<int>, greater<int> > pq;

// 结构体中符号重载,< 表示大的在前,> 表示小的在前(对应greater)
struct Node
{
    int val;
    // 自定义符号重载,< 表示大的在前,> 表示小的在前(对应greater)
    // bool operator<(const Node& other) const {
    //     return val < other.val; // 大的在前
    // }
};
// 结构体类型大根堆
priority_queue<Node, vector<Node> > pq;
// 在结构体外定义符号重载,< 表示大的在前,> 表示小的在前(对应greater)
bool operator<(Node a, Node b)  // 表示大的在前
{
    return a.val < b.val;
}

核心操作

// 插入元素
pq.push(x);
// 删除元素
pq.pop();
// 取队首元素
int top = pq.top();
// 判断堆是否为空
if (pq.empty()) { ... }
// 取堆的大小
int size = pq.size();

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 838 堆排序 简单 ⭐⭐⭐ 堆排序(小根堆) \(O(n)\) 建堆(从最后一个非叶子节点 \(n/2\) 开始逐个 down 调整),每次输出堆顶最小值后用最后一个元素覆盖堆顶并 down(1) 维护堆性质,重复 \(m\) 次输出前 \(m\) 小,建堆 \(O(n)\)、每次调整 \(O(\log n)\),总时间复杂度 \(O(n + m \log n)\)
AcWing 839 模拟堆 简单 ⭐⭐⭐⭐ 堆 + 双映射数组(维护"第k个插入元素"与堆下标的双向映射) 维护小根堆的同时用 pth[i](第 \(i\) 个插入元素在堆中的下标)和 htp[j](堆中下标 \(j\) 的元素是第几个插入的)实现 \(O(1)\) 定位任意插入元素,支持插入、查最小值、删最小值、删第 \(k\) 个插入元素、修改第 \(k\) 个插入元素五种操作,每次 down/up 调整 \(O(\log n)\)
AcWing 1263 最小函数值
AcWing 3531 哈夫曼树
AcWing 6051 看病
AcWing 6052 小明的账单
洛谷 AT_abc419_b Get Min 入门
洛谷 AT_abc423_d Long Waiting 普及
洛谷 AT_abc424_e Cut in Half 普及
洛谷 P1801 黑匣子 普及
洛谷 P3378 堆 普及
洛谷 P1631 序列合并 普及+
洛谷 P2827 蚯蚓 提高+
AtCoder AT_awc0008_d Orchard Harvest
AtCoder AT_awc0012_d Escape from the Maze
AtCoder AT_awc0043_b Pairing for the Dance Party ⭐⭐⭐ 贪心 + 双堆(最大堆 + 小顶堆) 用最大堆按优先级维护未配对参与者,为每个参与者用小顶堆维护其配对候选(按编号升序),每次取出优先级最高的参与者 \(x\),从其候选小顶堆中找到第一个未配对的 \(y\) 进行配对,重复直到全部配对完成,输出参与者 \(1\) 的配对对象,时间复杂度 \(O((N+M) \log N)\)

【其他排序】

算法模板

struct Node
{
	int t, d;  // 定义结构体成员
}a[N];

bool cmp(Node x, Node y)
{
	if (x.t != y.t) return x.t < y.t;  // 使用不等的方式来求保证优先排序
	return x.d < y.d;
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 425 明明的随机数
AcWing 429 奖学金
AcWing 438 分数线划定
AcWing 3446 整数奇偶排序
AcWing 4087 插入排序
AcWing 5909 车厢重组
AcWing 5911 谁考了第k名
AcWing 5912 奇数单增序列
AcWing 5913 成绩排序
AcWing 5914 合影效果
AcWing 5915 病人排队
AcWing 5916 单词排序
AcWing 5917 出现次数超过一半的数
AcWing 5918 统计字符数
AcWing 5974 不重复地输出数
洛谷 AT_abc355_b Piano 2 入门
洛谷 AT_abc394_b cat 入门
洛谷 AT_abc440_b Trifecta 入门
洛谷 P1152 欢乐的跳 入门
洛谷 P11445 调皮的学生 入门
洛谷 AT_abc348_c Colorful Beans 普及-
洛谷 AT_abc350_c Sort 普及-
洛谷 AT_abc354_c AtCoder Magics 普及-
洛谷 AT_abc384_c Perfect Standings 普及-
洛谷 AT_abc398_c Uniqueness 普及-
洛谷 AT_abc399_b Ranking with Ties 普及-
洛谷 AT_abc428_b Most Frequent Substrings 普及-
洛谷 [[B3968 成绩排序]] 普及-
洛谷 B4041 区间排序 普及-
洛谷 [[B4104 购物]] 普及-
洛谷 [[B4361 排序]] 普及-
洛谷 [[B4416 最长连续段]] 普及-
洛谷 [[B4452 优先购买]] 普及-
洛谷 [[B4502 礼盒排序]] 普及- 结构体 + 自定义比较器排序 读入时同步计算每个礼盒的总价格 tot、最贵 maxn、最便宜 minn,封装为结构体后按四重优先级(totmaxnminnid)自定义 cmp 比较器排序,最后输出排序后的礼盒编号,时间复杂度 \(O(n \cdot k + n \log n)\),空间复杂度 \(O(n)\)
洛谷 P1059 明明的随机数 普及-
洛谷 P1068 分数线划定 普及-
洛谷 P1093 奖学金 普及-
洛谷 P1097 统计数字 普及-
洛谷 P1104 生日 普及-
洛谷 P1116 车厢重组 普及-
洛谷 [[P1204 挤牛奶]] 普及-
洛谷 P1271 选举学生会 普及-
洛谷 [[P2913 Wheel Rotation]] 普及-
洛谷 [[P2965 The Grand Farm-off]] 普及-
洛谷 P3955 图书管理员 普及-
洛谷 P5143 攀爬者 普及-
洛谷 P7072 直播获奖 普及-
洛谷 [[P8267 Counting Liars]] 普及-
洛谷 [[P8897 Cow College]] 普及-
洛谷 [[P9959 Sleepy Cow Sorting]] 普及-
洛谷 [[P12134 画展布置]] 普及-
洛谷 P14357 拼数 普及-
洛谷 P14358 座位 普及-
洛谷 AT_abc355_d Intersecting Intervals 普及
洛谷 AT_abc413_d Make Geometric Sequence 普及
洛谷 P1012 拼数 普及
洛谷 P1309 瑞士轮 普及
洛谷 P5682 次大值 普及
洛谷 P7910 插入排序 普及
洛谷 [[P8092 Drought]] 普及
洛谷 [[P9957 Stuck in a Rut]] 普及
AtCoder AT_awc0001_b Exam Passers
AtCoder AT_awc0007_c Group Knockout Battle
AtCoder AT_awc0009_d Planting Flower Seeds
AtCoder AT_awc0016_c Choosing Souvenirs
AtCoder AT_awc0027_b Election of the Class President
AtCoder AT_awc0088_b Bus Tour Group Division
学而思编程 毕业照 语言基础 自定义排序 奇数按升序排在前半段,偶数按降序排在后半段,一奇一偶时奇数优先。
学而思编程 数位排序 语言基础 自定义排序 按数位和升序排序,数位和相同时按数值大小升序排序。
学而思编程 最大整数(一) 普及奠基 ⭐⭐ 自定义排序 将数字按奇偶性分离,各自降序排序后按原位置奇偶性回填,得到最大整数。

【双指针】

算法模板

基本声明方式(for+while)

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;  // 这里while的内容也跟着题目要求变化
    // 具体问题的逻辑
}

基本声明方式(while)

while (i<=n && j<=m)
{
    if (...)
    {  // 同时移动
        i++;
        j++;
        ...
    }
    else  // 单个指针移动(是i移动或j移动根据题意而不同)
        j++;
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 467 海港
AcWing 799 最长连续不重复子序列 简单 ⭐⭐ 双指针(滑动窗口) 用频率数组 \(s[x]\) 记录窗口内每个数字出现次数,右指针 \(i\) 向右扩展并增加计数,若 \(s[a[i]] > 1\) 则左指针 \(j\) 右移收缩窗口直到无重复,每次更新最大长度 \(ans = \max(ans, i-j+1)\),时间复杂度 \(O(n)\)
AcWing 800 数组元素的目标和 简单 ⭐⭐ 双指针(对撞指针) 利用两数组升序的单调性,指针 \(i\)\(A\) 头向右遍历,指针 \(j\)\(B\) 尾向左移动:若 \(A[i]+B[j] > x\)\(j\) 左移寻找更小的 \(B[j]\),若等于 \(x\) 则找到答案,时间复杂度 \(O(n+m)\)
AcWing 2816 判断子序列
洛谷 [[P9950 Mad Scientist]] 入门
洛谷 AT_abc329_c Count xxx 普及-
洛谷 AT_abc352_b Typing 普及-
洛谷 AT_abc460_c Sushi 普及- ⭐⭐ 排序 + 双指针贪心 将舍利重量数组 \(A\) 和配料重量数组 \(B\) 分别升序排序后,用双指针遍历:若当前配料 \(B_j \leq 2 \times A_i\) 则配对成功(\(ans++\),两指针均右移),否则 \(i\) 右移寻找重量更大的舍利,最终输出最大配对数 \(ans\),时间复杂度 \(O(N \log N + M \log M)\)
洛谷 AT_abc464_c Plumage Palette 普及- ⭐⭐⭐ 双指针 + 哈希表(map 将所有鸟按变色天数 \(D_i\) 升序排序,用 map 维护当前各颜色的鸟的数量,初始时所有鸟为颜色 \(A_i\);然后用双指针遍历天数 \(i=1 \sim M\),对于每一天将所有 \(D_j = i\) 的鸟从颜色 \(A_j\) 改为 \(B_j\)(对应 map 中计数减1/加1,计数为0时删除),每天输出 map.size() 即为当天颜色种类数,时间复杂度 \(O(N \log N + M + N \log N)\)(排序 + 遍历 + map 操作),空间复杂度 \(O(N)\)
洛谷 [[B3928 田忌赛马]] 普及-
洛谷 [[B4006 宝箱]] 普及-
洛谷 P1147 连续自然数和 普及-
洛谷 [[P3669 Paired Up]] 普及-
洛谷 P11231 决斗 普及-
洛谷 AT_abc377_d Many Segments 2 普及
洛谷 AT_abc381_d 1122 Substring 普及
洛谷 AT_abc384_d Repeated Sequence 普及
洛谷 AT_abc389_d Squares in Circle 普及
洛谷 AT_arc098_b Xor Sum 2 普及
洛谷 P1638 逛画展 普及
洛谷 [[P2649 游戏预言]] 普及
洛谷 P3029 Cow Lineup 普及
洛谷 [[P5541 Sleepy Cow Herding]] 普及
洛谷 P1381 单词背诵 普及+
洛谷 AT_abc361_g Go Territory 省选
洛谷 [[AT_abc466_c Count Close Pairs]]
AtCoder AT_awc0002_d Keys and Treasure Boxes ⭐⭐ 排序 + 双指针贪心 将宝箱锁强度 \(C\) 和钥匙开启能力 \(R\) 分别升序排序后,用双指针遍历:若当前钥匙 \(R_j < C_i\)\(j\) 右移跳过无法匹配的钥匙,否则配对成功(\(i++\)\(j++\)\(cnt++\)),输出最大匹配数 \(cnt\),时间复杂度 \(O(N \log N + M \log M)\)
AtCoder AT_awc0015_d Assignment of Cooking Tasks ⭐⭐⭐ 排序 + 双指针贪心 将工作人员技能等级数组 \(A\) 和任务所需技能等级数组 \(B\) 分别升序排序后,用双指针遍历:若当前工作人员技能 \(A_j \geq\) 当前任务需求 \(B_i\) 则匹配成功(\(ans++\),两指针均右移),否则 \(j\) 右移寻找技能更高的工作人员,最终答案为 \(ans \times C\),时间复杂度 \(O(N \log N + M \log M)\)
AtCoder AT_awc0016_d The Path of Carrying Luggage ⭐⭐⭐ 双指针 + 前缀和 预处理前缀和数组 \(sa\) 后,用双指针维护窗口:右指针 \(j\) 扩展直到区间和超过 \(K\) 或到达末尾,记录 \(f[i]=j\) 后左指针 \(i\) 右移,由于包裹重量为正,\(j\) 不会回退保证总移动 \(O(N)\);再对 \(f\) 数组求前缀和 \(sf\),每个查询 \([L,R]\) 的答案为 \(sf[R]-sf[L-1]\),总时间复杂度 \(O(N+Q)\)
AtCoder AT_awc0026_e Just the Right Temperature Difference ⭐⭐⭐ 双指针 + 单调队列 + 容斥原理 双指针维护滑动窗口,两个单调队列分别维护窗口内的最小值(单调递增)和最大值(单调递减),实现 \(O(1)\) 查询区间极值;右指针扩展时入队维护单调性,当 max - min > k 时左指针收缩并弹出过期元素,统计以当前右端点结尾的满足条件的区间数;最后通过容斥 calc(K) - calc(K-1) 将"差值不超过 \(K\)"转化为"差值恰好等于 \(K\)",两次 \(O(N)\) 遍历得到答案。
AtCoder AT_awc0032_d Part-Time Job Shift Assignment
AtCoder AT_awc0083_c Laying Optical Fiber ⭐⭐⭐ 双指针(滑动窗口) 用滑动窗口维护成本不超过 \(M\) 的连续区间,右指针 \(r\) 从左到右遍历并累加成本,当成本超限时左指针 \(l\) 右移收缩窗口,每次窗口合法时更新最大位置差 \(X_r - X_l\),时间复杂度 \(O(N)\)
AtCoder AT_awc0087_c Shortest Mountain Climbing Route ⭐⭐⭐ 滑动窗口(双指针) 用滑动窗口维护区间 \([l,r]\) 的总海拔变化(相邻海拔差绝对值之和),右指针 \(r\) 向右扩展累加 $ \
AtCoder AT_awc0089_c A Walk to Cherry Blossom Viewing ⭐⭐⭐ 滑动窗口(双指针) 用滑动窗口维护散步道区间 \([l,r]\) 的成本和满意度,右指针 \(r\) 扩展时累加 \(P_{r+1}\)\(C_r\),当成本超预算时左指针 \(l\) 右移收缩窗口并扣除对应成本与分数,每次窗口合法时更新最大满意度 \(ans = \max(ans, sumP)\),时间复杂度 \(O(N)\)
学而思编程 气球游戏 普及奠基 ⭐⭐⭐ 双指针 / 滑动窗口 维护包含所有 \(m\) 种颜色的最小窗口,右扩左缩,队首冗余时出队优化。

【贪心】

算法模板

// 贪心没有固定的模板,但一般都涉及到排序

// 大部分贪心可以先假设,再验证,少量贪心需要数学公式证明,例如 a*b 或 a/b 等等

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 104 货仓选址
AcWing 125 耍杂技的牛
AcWing 148 合并果子 简单 ⭐⭐⭐ 贪心 + 哈夫曼编码(小根堆) 将所有果子数量放入小根堆,每次取出最小的两堆合并(代价累加为 \(x+y\)),再将合并后的新堆放回堆中,重复 \(n-1\) 次直到只剩一堆,总代价即为最小体力耗费,时间复杂度 \(O(n \log n)\)
AcWing 442 接水问题
AcWing 803 区间合并 简单 ⭐⭐ 贪心 + 排序 将所有区间按左端点升序排序后线性扫描,维护当前合并区间的起止点 \((st,ed)\):若新区间左端点 \(l > ed\) 则将 \([st,ed]\) 加入结果并开始新区间,否则合并为 \(ed = \max(ed,r)\),最后处理最后一个区间,输出结果数量,时间复杂度 \(O(n \log n)\)
AcWing 905 区间选点
AcWing 906 区间分组
AcWing 907 区间覆盖
AcWing 908 最大不相交区间数量
AcWing 913 排队打水
AcWing 1536 均分纸牌
AcWing 3360 牛棚
AcWing [[4171 智力大冲浪]]
AcWing 5942 排队接水
AcWing 5943 删数问题
AcWing 5944 活动选择
AcWing 5945 整数区间
AcWing 5946 一个简单问题
AcWing 5947 金银岛
AcWing 5948 装箱问题
AcWing 5949 骑车上班
AcWing 5950 书架
AcWing 5951 电池的寿命
AcWing 5952 寻找平面上的极大点
AcWing 5953 最小新整数
AcWing 5954 过河
AcWing 5961 区间合并
洛谷 AT_abc373_c Max Ai+Bj 入门
洛谷 [[P1639 Teleportation]] 入门
洛谷 AT_abc332_c T-shirts 普及-
洛谷 AT_abc352_c Standing On The Shoulders 普及-
洛谷 AT_abc360_c Move It 普及-
洛谷 AT_abc361_c Make Them Narrow 普及-
洛谷 AT_abc362_c Sum = 0 普及-
洛谷 AT_abc364_c Minimum Glutton 普及-
洛谷 AT_abc370_c Word Ladder 普及-
洛谷 AT_abc396_c Buy Balls 普及-
洛谷 AT_abc416_b 1D Akari 普及-
洛谷 AT_abc421_c Alternated 普及-
洛谷 AT_abc422_c AtCoder AAC Contest 普及-
洛谷 AT_abc423_c Lock All Doors 普及-
洛谷 AT_abc441_c Sake or Water 普及-
洛谷 AT_abc461_c Variety 普及-
洛谷 [[B3959 做题]] 普及-
洛谷 B4051 小杨的武器 普及-
洛谷 [[B4359 分糖果]] 普及-
洛谷 B4377 交换字符 普及-
洛谷 P1031 均分纸牌 普及-
洛谷 P1094 纪念品分组 普及-
洛谷 P1109 学生分组 普及-
洛谷 P1190 接水问题 普及-
洛谷 P1208 混合牛奶 普及-
洛谷 P1223 排队接水 普及-
洛谷 [[P1376 机器工厂]] 普及-
洛谷 [[P1459 三值的排序]] 普及-
洛谷 P1478 涛涛摘苹果(升级版) 普及-
洛谷 P1496 火烧赤壁 普及-
洛谷 P1803 线段覆盖 普及-
洛谷 P2240 部分背包问题 普及-
洛谷 P2616 Buying Feed, II 普及-
洛谷 P2676 Bookshelf 普及-
洛谷 [[P2909 Cow Cars]] 普及-
洛谷 [[P2945 Sand Castle]] 普及-
洛谷 [[P3650 滑雪课程设计]] 普及-
洛谷 P3817 小A的糖果 普及-
洛谷 [[P4379 Lemonade Line]] 普及-
洛谷 P4995 跳跳 普及-
洛谷 P5690 日期 普及-
洛谷 P6244 Country Fair Events 普及-
洛谷 P7427 玩游戏 普及-
洛谷 P7666 寒冬暖炉 普及-
洛谷 P8597 翻硬币 普及-
洛谷 P8697 最长子序列 普及-
洛谷 P8739 重复字符串 普及-
洛谷 P8837 商店 普及-
洛谷 [[P9121 Hungry Cow]] 普及-
洛谷 [[P9123 Watching Mooloo]] 普及-
洛谷 P9749 公路 普及-
洛谷 P9868 词典 普及-
洛谷 P10452 货仓选址 普及-
洛谷 AT_abc334_c Socks 2 普及
洛谷 AT_abc347_c Ideal Holidays 普及
洛谷 AT_abc386_d Diagonal Separation 普及
洛谷 AT_abc399_d Switch Seats 普及
洛谷 AT_abc401_d Logical Filling 普及
洛谷 AT_abc408_d Flip to Gather 普及
洛谷 AT_abc409_d String Rotation 普及
洛谷 AT_abc412_c Giant Domino 普及
洛谷 AT_abc414_d Transmission Mission 普及
洛谷 AT_abc415_d Get Many Stickers 普及
洛谷 AT_abc416_d Match, Mod, Minimize 2 普及
洛谷 [[B3872 巧夺大奖]] 普及
洛谷 [[B3930 烹饪问题]] 普及
洛谷 B4071 武器强化 普及
洛谷 CF1486B Eastern Exhibition 普及
洛谷 P1007 独木桥 普及
洛谷 P1016 旅行家的预算 普及
洛谷 P1056 排座椅 普及
洛谷 P1090 合并果子 普及
洛谷 P1095 守望者的逃离 普及
洛谷 P1106 删数问题 普及
洛谷 P1158 导弹拦截 普及
洛谷 [[P1167 刷题]] 普及
洛谷 P1199 三国游戏 普及
洛谷 [[P1209 修理牛棚]] 普及
洛谷 [[P1230 智力大冲浪]] 普及
洛谷 [[P1338 末日的传说]] 普及
洛谷 [[P1694 The Great Revegetation]] 普及
洛谷 [[P1842 奶牛玩杂技]] 普及
洛谷 P1843 奶牛晒衣服 普及
洛谷 P1969 积木大赛 普及
洛谷 P2878 Protecting the Flowers 普及 ⭐⭐⭐ 自定义排序贪心 + 后缀和 通过交换论证推导出按 \(T_i/D_i\) 升序排序(即 \(T_i \times D_j < T_j \times D_i\)\(i\) 先赶),排序后预处理后缀和 \(sa[i]\) 表示从第 \(i\) 个任务到最后的总时间,总代价为 \(\sum_{i=1}^{n} 2 \times D_i \times sa[i+1]\),时间复杂度 \(O(n \log n)\)
洛谷 [[P2902 Pearl Pairing]] 普及
洛谷 [[P3078 Poker Hands]] 普及
洛谷 P5019 铺设道路 普及
洛谷 P7076 动物园 普及
洛谷 [[P7994 Air Cownditioning]] 普及
洛谷 [[P9975 Cowntact Tracing 2]] 普及
洛谷 P11229 小木棍 普及
洛谷 [[P11247 算法学习]] 普及
洛谷 [[P11960 平均分配]] 普及
洛谷 P14359 异或和 普及
洛谷 P14361 社团招新 普及
洛谷 P15256 Purchasing Milk 普及 ⭐⭐⭐⭐ 贪心 + 二进制分解 + 价格预处理 预处理价格使 \(a_i = \min(a_i, 2 \cdot a_{i-1})\) 保证合理性,并记录 \(i \geq 32\) 时的最低价格作为保底;对每个查询 \(x\),从大到小枚举前31个交易(\(base = 2^{i-1}\)),贪心购买 \(x/base\) 个当前交易,计算候选答案(有余数则多买一个),同时更新剩余需求 \(x \%= base\),最终输出最小花费,单次查询 \(O(\log x)\)
洛谷 P1080 国王游戏 普及+
洛谷 P1809 过河问题 普及+ ⭐⭐⭐ 贪心 将过河时间升序排序后,从后往前每次送最慢的两人过河,比较两种方案取最小:方案1(最快+次快过去→最快回来→最慢+次慢过去→次快回来,耗时 \(t_2+t_1+t_{idx}+t_2\))与方案2(最快+最慢过去→最快回来→最快+次慢过去→最快回来,耗时 \(t_{idx-1}+t_1+t_{idx}+t_1\)),剩余2人直接一起过,剩余3人特殊处理,时间复杂度 \(O(N \log N)\)
洛谷 P2114 起床困难综合征 普及+
洛谷 [[P2376 Allowance]] 普及+
洛谷 [[P3173 巧克力]] 普及+
洛谷 P4016 负载平衡问题 普及+ ⭐⭐⭐⭐ 贪心 + 中位数 计算平均值 \(avg\) 后,从第一个仓库开始贪心传递:第 \(i\) 个仓库需要调整 \(t = avg - a[i]\),将差额传给下一个仓库并记录传递量 \(b[i+1] = t\),累加 $\
洛谷 P4447 分组 普及+
洛谷 P5687 网格图 普及+
洛谷 P6033 合并果子 加强版 普及+
洛谷 P7915 回文 普及+
洛谷 P10134 Cowmpetency 普及+
洛谷 P11232 超速检测 普及+
洛谷 P1315 观光公交 提高+
洛谷 P2512 糖果传递 提高+
洛谷 P2672 推销员 提高+
洛谷 P3076 Taxi 提高+
洛谷 P4053 建筑抢修 提高+
洛谷 P11361 编辑字符串 提高+
洛谷 [[AT_abc466_d Placing Rooks]]
AtCoder AT_awc0001_c Discount Coupon
AtCoder AT_awc0003_c Bargain Sale Selection
AtCoder AT_awc0004_c Minimum Cost of Temperature Adjustment
AtCoder AT_awc0004_d Parking Lot Assignment ⭐⭐⭐ 贪心 + 排序 将车辆按右端点 \(R_i\) 升序排序(\(R_i\) 相同则按 \(L_i\) 升序),然后贪心遍历每辆车,在其区间 \([L_i, R_i]\) 内从左到右扫描分配第一个空闲停车位,若某辆车无法分配则输出 No,否则全部分配成功输出 Yes,时间复杂度 \(O(M \log M + N \times M)\)
AtCoder AT_awc0006_d Placement of Security Guards ⭐⭐⭐ 贪心(区间覆盖) 将所有区间按左端点升序排序后,维护当前已覆盖的最右位置 \(r\),每次在左端点不超过 \(r+1\) 的区间中选择右端点最大的区间扩展覆盖范围,若某步无法扩展或出现断层(\(L_i > r+1\))则输出 \(-1\),否则覆盖到 \(N\) 后输出使用区间数,时间复杂度 \(O(M \log M)\)
AtCoder AT_awc0010_d Rock Destruction
AtCoder AT_awc0012_c Team Formation
AtCoder AT_awc0013_c Optimal Pairing for a Tournament
AtCoder AT_awc0014_a Loading Cargo 贪心 / 模拟 每辆卡车独立计算,重量限制下最多装载 \(\lfloor T / P_i \rfloor\) 件,数量限制为 \(R\) 件,取两者较小值 \(r_i = \min(R, \lfloor T / P_i \rfloor)\) 即为最大装载量,时间复杂度 \(O(N)\)
AtCoder AT_awc0019_c Consecutive Card Distribution
AtCoder AT_awc0019_e Loading Cargo 模拟 对每辆卡车独立计算重量限制下的最大件数 \(\lfloor T / P_i \rfloor\),再与数量上限 \(R\) 取较小值即得该卡车最大装载量 \(r_i = \min(R, T / P_i)\),时间复杂度 \(O(N)\)
AtCoder AT_awc0020_c Organizing the Bookshelf
AtCoder AT_awc0020_d Wi-Fi Spot Connection
AtCoder AT_awc0021_c Bargain Shopping Mall Tour
AtCoder AT_awc0025_c Air Conditioning Installation in Classrooms
AtCoder AT_awc0026_c Field Trip Snacks
AtCoder AT_awc0028_c Make-Up Exam
AtCoder AT_awc0029_c Formation of the Strongest Pair
AtCoder AT_awc0031_d Library Inventory Check ⭐⭐⭐⭐ 贪心 + 排序 + 二分查找 将每天检查上限 \(L\) 升序排序、书籍需求 \(R\) 降序排序后,遍历每本书累加需求 \(sumr\),同时用 lower_bound 找到第一个 \(L \geq i\) 的位置,累加能力达标的天数 \(suml\),若某时刻 \(suml < sumr\) 则输出 No,否则遍历完输出 Yes,时间复杂度 \(O(N \log N + M \log M + M \log N)\)
AtCoder AT_awc0033_b Plant Temperature Management
AtCoder AT_awc0046_c Seating Arrangement ⭐⭐⭐ 贪心 从左到右遍历每个空座位,检查三种冲突情况:左右均占 \((s_{i-1}=1,s_{i+1}=1)\)、左侧连续两占 \((s_{i-2}=1,s_{i-1}=1)\)、右侧连续两占 \((s_{i+1}=1,s_{i+2}=1)\),若均不冲突则安排客人并标记 \(s_i=1\),累加答案,时间复杂度 \(O(N)\)
AtCoder AT_awc0047_d Equal Distribution of Cake
AtCoder AT_awc0087_b Factory Machine Maintenance
AtCoder AT_awc0087_d Returning Library Books ⭐⭐⭐ 贪心 + 分组 将书架坐标按正负分离,正数降序排序、负数升序排序(均为绝对值从大到小),每次取最远的 \(K\) 本书为一组处理,每组往返距离为 \(2 \times\) 该组最远距离,累加所有组距离得最小总移动距离,时间复杂度 \(O(N \log N)\)
AtCoder AT_awc0089_b Connecting Pipes
学而思编程 乘积最大 普及进阶 ⭐⭐⭐⭐ 贪心(数字分配 + 数位调整) 将数字各位从大到小排序后循环分配到三个数中,若位数不是 3 的倍数则补 0 使三数位数相同;贪心调整策略为:让最大数 v[1] 尽可能小(与 v[3] 交换使 v[1] 变小),同时让后两个数 v[2]v[3] 的差值尽可能小(确定大小关系后交换使较小者变大),最终三个数的乘积最大,时间复杂度 \(O(d^2)\)\(d\) 为数字位数,\(d \le 18\))。
学而思编程 排队 普及奠基 ⭐⭐ 贪心 / 排序 按耐心指数升序排序,依次尝试安排,若当前已安排人数 \(\leq a_i\) 则该学生留下,否则跳过。

【反悔贪心】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 P14635 糖果店 普及
洛谷 CF865D Buy Low Sell High 提高+
洛谷 [[P2949 Work Scheduling]] 提高+

【位运算】

算法模板

// 求n的第k位数字(0或1):
n >> k & 1

// 如果一个整数需要转换为二进制,可用标准的方式,但是如果转为的二进制有固定长度,高位补0,则可以
for (int i = l - 1; i >= 0; i--)  // 从最高位到最低位输出二进制结果
	cout << ((ans >> i) & 1LL);   // 取出 ans 的第 i 位并输出

// 返回n的最后一位1:
lowbit(n) = n & -n

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 90 64位整数乘法
AcWing 801 二进制中1的个数 简单 位运算(lowbit) 利用 lowbit(x) = x & -x 提取二进制最低位的 \(1\),每次减去 lowbit(x) 消去一个 \(1\) 并计数,直到 \(x\) 变为 \(0\),统计次数即为 \(1\) 的个数,时间复杂度 \(O(n \cdot \log x)\)
AcWing 1875 贝茜的报复
AcWing 3481 阶乘的和
AcWing 3646 分水果
AcWing 3706 不连续1的子串
AcWing 4201 01数
洛谷 B4261 2025 入门
洛谷 [[B4358 奇偶校验]] 入门
洛谷 [[B4106 翻硬币]] 普及-
洛谷 B4302 出现奇数次的数 普及-
洛谷 [[B4357 幂和数]] 普及-
洛谷 AT_abc356_d Masked Popcount 普及
洛谷 [[P1461 海明码]] 普及
洛谷 P1965 转圈游戏 普及
洛谷 P11965 等价消除 普及
AtCoder AT_awc0011_c Maximum Number of Team Members
AtCoder AT_awc0082_b Maximizing the Partition Score of a Lamp Sequence ⭐⭐⭐⭐ 位运算 + 枚举 对初始状态 \(X\) 进行最多 \(K\) 次循环左移(最低位为 \(0\) 时右移一位并在最高位补 \(1\)),将处理后的 \(X\) 加入 \(Y\) 数组后,枚举分割位置 \(p\)\(1\)\(N-1\)),用掩码 \(t = (1 \ll p) - 1\) 提取低 \(p\)\((y_i \& t)\) 和高 \(N-p\)\((y_i \gg p)\),累加所有数的两部分之和并更新最大值,时间复杂度 \(O(K + N \cdot M)\)
AtCoder AT_awc0100_c Permission Management System ⭐⭐⭐ 位运算(按位或) 将每个资源的权限二进制串转为整数存储,对于每次查询,将所有需要访问的资源对应的整数值进行按位或运算,结果即为满足所有资源访问要求且值最小的权限串(按位或恰好覆盖所有需要的1,不多设不必要的权限),最后将结果按位输出为长度为 \(L\) 的二进制串,时间复杂度 \(O(N \times L + Q \times M \times L)\)\(M\) 为单次查询资源数),空间复杂度 \(O(N)\)

【递推】

算法模板

// 最经典的递推,斐波那契数列
f[n] = f[n-1] + f[n-2];

// 递推题可以在摸索到数字规律后使用 f[] 的公式形式来表达

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing [[95 费解的开关]]
AcWing 3433 吃糖果
AcWing 5493 过河卒
AcWing 5496 数的计算
AcWing 5919 昆虫繁殖
AcWing 5920 位数问题
AcWing 5921 菲波那契数列(2)
AcWing 5922 Pell数列
AcWing 5923 上台阶
AcWing 5925 移动路线
AcWing 5926 判断整除
AcWing 5927 踩方格
AcWing 5928 山区建小学
AcWing 5929 集合的划分
AcWing 5935 放苹果
AcWing 5936 求最大公约数问题
AcWing 5938 因子分解
AcWing 5955 循环比赛日程表
洛谷 AT_abc427_b Sum of Digits Sequence 入门
洛谷 AT_abc369_c Count Arithmetic Subarrays 普及-
洛谷 P1002 过河卒 普及-
洛谷 P1028 数的计算 普及-
洛谷 P1044 栈 普及-
洛谷 P1164 小A点菜 普及-
洛谷 P1216 数字三角形 普及-
洛谷 P1244 青蛙过河 普及-
洛谷 P1287 盒子与球 普及-
洛谷 P2837 Dining Cows 普及-
洛谷 P1113 杂务 普及
洛谷 [[P1311 选择客栈]] 普及
洛谷 [[P1466 集合]] 普及
洛谷 P1990 覆盖墙壁 普及
洛谷 [[P6065 Sumsets]] 普及
洛谷 P9014 Following Directions 普及
洛谷 P1982 小朋友的数字 普及+
洛谷 P5023 填数游戏 省选
学而思编程 斐波那契字符串 普及奠基 递推 / 模拟 生成不超过 \(n\) 的斐波那契数列,标记对应位置,斐波那契数输出 O,其余输出 o
学而思编程 牛奶供应 普及奠基 ⭐⭐⭐ 递推 / 贪心 维护最小有效价格 \(\text{minp}\),每天选择当天生产或从前某天提前生产(加仓储费),取成本最小者。
学而思编程 三倍子串 普及奠基 ⭐⭐⭐ 递推 / DP \(\text{dp}[i][r]\) 表示以 \(s[i]\) 结尾、数字和模 \(3\)\(r\) 的子串数,根据当前位模 \(3\) 的值转移。

【离散化】

算法模板

结构体方式离散化

//对原有数组去重
struct Node
{
    int val, pos, newval;
}a[N];
bool cmp(Node x, Node y)
{
    return x.val < y.val;
}
bool cmp2(Node x, Node y)
{
    return x.pos < y.pos;
}

for (int i=1; i<=n; i++)
{
    cin >> a[i].val;
    a[i].pos = i;
}
sort(a+1, a+n+1, cmp);
int cnt = 0;
for (int i=1; i<=n; i++)
{
    if (a[i].val!=a[i-1].val)
        cnt++;
    a[i].newval = cnt;
}
sort(a+1, a+n+1, cmp2);  // 根据pos,从小到大还原
// 以下为示例
/*
7
10 9 7 11 10 8 6
1 10 5
2 9 4
3 7 2
4 11 6
5 10 5
6 8 3
7 6 1
14
*/

vector方式离散化

vector<int> alls;            // 存储所有需要离散化的坐标
// 离散化处理:排序并去重
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());

// 处理插入操作(离散化后)
for (auto item : add)
{
    int x = find(item.first);   // 获取离散化后的坐标
    a[x] += item.second;        // 在对应位置累加值
}

int find(double y)
{
	return lower_bound(alls.begin(), alls.end(), y) - alls.begin();
}

int find(int x)
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = (l + r) >> 1;
        if (alls[mid] >= x)
            r = mid;
        else
            l = mid + 1;
    }
    return r + 1;  // 返回离散化后的索引(从1开始)
}

// 对关键点排序并去重
sort(a + 1, a + cnt + 1);
cnt = unique(a + 1, a + cnt + 1) - a - 1;  // 更新实际关键点数量

非保序离散化

unordered_map<int, int> S;
int get(int x)
{
    if (S.count(x)==0) S[x] = ++n;
    return S[x];
}

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
AcWing 802 区间和 简单 ⭐⭐⭐ 离散化 + 前缀和 将所有涉及的坐标(插入点和查询端点)收集后排序去重得到离散化映射,用 find(x) 二分查找离散化后的位置,在离散化数组上执行单点加和前缀和查询,回答区间和为 \(s[r] - s[l-1]\),时间复杂度 \(O((n+m) \log(n+m))\)
洛谷 P1904 天际线 普及-
洛谷 AT_abc371_d 1D Country 普及
洛谷 P1884 Overplanting 普及+
AtCoder AT_awc0089_e Painting the Fence ⭐⭐⭐⭐⭐ 离散化 + 扫描线 + 差分 将区间端点离散化后,用扫描线维护当前覆盖每段的区间集合 \(S\),若 \(S\) 非空且区间编号连续跨度 \(\leq K\)\(mx-mn+1 \leq K\)),则用差分数组记录该段可被覆盖的起始范围:\(diff[mn+1] += len\)\(diff[\max(0,mn-(K-(mx-mn+1)))] -= len\),最后对差分数组求前缀和,\(n+diff[i]\) 即为从位置 \(i\) 开始忽略 \(K\) 个连续指令后的覆盖长度,取最大值,时间复杂度 \(O(M \log M)\)

【倍增】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 AT_abc438_e Heavy Buckets 普及
洛谷 P1816 忠诚 普及
洛谷 [[P3083 Luxury River Cruise]] 普及

【构造】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 AT_abc422_d Least Unbalanced 普及
洛谷 P8902 Range Reconstruction 普及+
洛谷 [[P14975 COW Splits]] 普及+

【随机化】

算法模板

算法应用

题目来源 标题 难度 星级 考察算法 一句话思路总结
洛谷 AT_abc422_e Colinear 普及+
posted @ 2026-06-27 14:22  团爸讲算法  阅读(26)  评论(0)    收藏  举报