2026-02-13~16 hetao1733837 的刷题记录

2026-02-13~16 hetao1733837 的刷题记录

02-13

LGP4590 [TJOI2018] 游园会

原题链接:[TJOI2018] 游园会

分析

我绝对见过这个题!是不是谁给我推过?

这和 DP 有毛关系?

哈哈,看完 tag 笑了......这是啥?我还是直接看 PPT 吧。

慢慢来......

我们设 L C S x , y LCS_{x,y} LCSx,y 表示 A 串前 x 位,B 串前 y 位的最长公共子序列长度,则
{ L C S x − 1 , y − 1 + 1 , A x = B y max ⁡ { L C S x − 1 , y , L C S x , y − 1 } , A x ≠ B y \begin{cases} LCS_{x-1,y-1}+1,A_x=B_y \\ \max\{LCS_{x-1,y},LCS_{x,y-1}\},A_x \neq B_y \end{cases} {LCSx−1,y−1+1,Ax=Bymax{LCSx−1,y,LCSx,y−1},Ax=By

然后,我们发现新的串基本是从上一个转过来的,且差为 0/1 ,进行状压,在状态中加判断使不出现 NOI 即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
const int N = 1005, M = 105, O = 35005;
int n, k;
char s[M];
int dp[2][O][3];
int tr1[M], tr2[M], sz[O], ans[M];
int hAsh(int *a){
    int res = 0;
    for (int i = 0; i < k; i++){
        res |= (a[i + 1] - a[i]) << i;
    }
    return res;
}
void Hash(int *a, int res){
    for (int i = 0; i < k; i++){
        a[i + 1] = (res >> i) & 1;
    }
    for (int i = 1; i <= k; i++){
        a[i] += a[i - 1];
    }
}
void calc(int p1, int p2, int p3, char c, int val){
    Hash(tr1, p2);
    for (int i = 1; i <= k; i++){
        tr2[i] = max({tr2[i - 1], tr1[i], tr1[i - 1] + (c == s[i])});
    }
    int tp2 = hAsh(tr2);
    dp[p1][tp2][p3] = (dp[p1][tp2][p3] + val) % mod;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> k;
    cin >> (s + 1);
    for (int i = 1; i <= 32767; i++){
        sz[i] = sz[i >> 1] + (i & 1);
    }
    dp[0][0][0] = 1;
    for (int i = 0; i < n; i++){
        int p1 = (~i) & 1;
        int p2 = i & 1;
        for (int j = 0; j < (1 << k); j++)
            for (int l = 0; l < 3; l++)
                dp[p1][j][l] = 0;
        for (int j = 0; j < (1 << k); j++){
            if (dp[p2][j][0] != 0){
                calc(p1, j, 1, 'N', dp[p2][j][0]);
                calc(p1, j, 0, 'O', dp[p2][j][0]);
                calc(p1, j, 0, 'I', dp[p2][j][0]);
            }
            if (dp[p2][j][1] != 0){
                calc(p1, j, 1, 'N', dp[p2][j][1]);
                calc(p1, j, 2, 'O', dp[p2][j][1]);
                calc(p1, j, 0, 'I', dp[p2][j][1]);
            }
            if (dp[p2][j][2] != 0){
                calc(p1, j, 1, 'N', dp[p2][j][2]);
                calc(p1, j, 0, 'O', dp[p2][j][2]);
            }
        }
    }
    for (int i = 0; i < (1 << k); i++){
        for (int j = 0; j < 3; j++){
            ans[sz[i]] = (ans[sz[i]] + dp[n & 1][i][j]) % mod;
        }
    }
    for (int i = 0; i <= k; i++){
        cout << ans[i] << '\n';
    }
    return 0;
}

02-14

LGP4137 Rmq Problem / mex

原题链接:Rmq Problem / mex

分析

这个东西放到洛谷首页已经几亿年了,居然在今天题单碰到了。

开!呃...... mex ⁡ \operatorname{mex} mex 有什么性质呢?

不会了,看看题解吧......

权值线段树维护当前值最后一次出现的位置,然后离线一下即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
const int M = N * 40; 
int n, m, a[N];
int buc[N << 2], tp;
int rt[N];
int tot;
struct segtree{
    struct node{
        int ls, rs, val;
    }tr[M];
    void pushup(int p){
        tr[p].val = min(tr[tr[p].ls].val, tr[tr[p].rs].val);
    }
    void modify(int p, int &pos, int l, int r, int s, int val){
        pos = ++tot;
        tr[pos].ls = tr[p].ls;
        tr[pos].rs = tr[p].rs;
        if (l == r){
            tr[pos].val = val;
            return ;
        }
        int mid = (l + r) >> 1;
        if (s <= mid){
            modify(tr[p].ls, tr[pos].ls, l, mid, s, val);
        }
        else{
            modify(tr[p].rs, tr[pos].rs, mid + 1, r, s, val);
        }
        pushup(pos);
    }
    int query(int p, int l, int r, int s){
        if (!p || l == r){
            return buc[l];
        }
        int mid = (l + r) >> 1;
        if (tr[tr[p].ls].val >= s){
            return query(tr[p].rs, mid + 1, r, s);
        }
        else{
            return query(tr[p].ls, l, mid, s);
        }
    }
}T;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    buc[++tp] = 0;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
        buc[++tp] = a[i];
        buc[++tp] = a[i] + 1;
    }
    sort(buc + 1, buc + tp + 1);
    tp = unique(buc + 1, buc + tp + 1) - buc - 1;
    for (int i = 1; i <= n; i++){
        int pos = lower_bound(buc + 1, buc + tp + 1, a[i]) - buc;
        T.modify(rt[i - 1], rt[i], 1, tp, pos, i);
    }
    for (int cs = 1, l, r; cs <= m; cs++){
        cin >> l >> r;
        cout << T.query(rt[r], 1, tp, l) << '\n';
    }
    return 0;
}

02-16

LGP9990 [Ynoi Easy Round 2023] TEST_90

原题链接:[Ynoi Easy Round 2023] TEST_90

分析

题面简洁,是我喜欢的题。不是,咋还套了一个计数!值域是 1e6 ,看起来有搞头。

朴素做法显然是......可能是 n 4 n^4 n4,或者 n 5 n^5 n5?懒得算了......从 tag 入手,有一个 扫描线,怎么玩?

很诡异啊......即使某个数出现了偶数次,我也可以......

这个很典啊!维护最后一次出现的位置!

奇偶性搞一个疑惑,维护一下历史版本和,打两个 tag

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1000005;
int n, a[N], m;
struct node{
    int l, r, id;
}inp[N];
int buc[N], lst[N], ans[N];
vector<int> pos[N];
struct segtree{
    struct tree{
        int len, sum, cnt;
        int tag0, tag1, tag;
    }tr[N << 2];
    void pushup(int p){
        tr[p].sum = tr[p << 1].sum + tr[p << 1 | 1].sum;
        tr[p].cnt = tr[p << 1].cnt + tr[p << 1 | 1].cnt;
    }
    void add(int p, int tag0, int tag1){
        tr[p].sum += tr[p].cnt * tag1 + (tr[p].len - tr[p].cnt) * tag0;
        tr[p].tag0 += tag0;
        tr[p].tag1 += tag1;
    }
    void down(int p){
        if (tr[p].tag){
            tr[p << 1].tag ^= 1;
            swap(tr[p << 1].tag0, tr[p << 1].tag1);
            tr[p << 1].cnt = tr[p << 1].len - tr[p << 1].cnt;
            tr[p << 1 | 1].tag ^= 1;
            swap(tr[p << 1 | 1].tag0, tr[p << 1 | 1].tag1);
            tr[p << 1 | 1].cnt = tr[p << 1 | 1].len - tr[p << 1 | 1].cnt;
            tr[p].tag = 0;
        }
        if (tr[p].tag0 || tr[p].tag1){
            add(p << 1, tr[p].tag0, tr[p].tag1);
            add(p << 1 | 1, tr[p].tag0, tr[p].tag1);
            tr[p].tag0 = tr[p].tag1 = 0;
        }
    }
    void build(int p, int l, int r){
        tr[p].len = r - l + 1;
        if (l == r){
            return ;
        }
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
    }
    void modify(int p, int l, int r, int s, int t){
        if (s <= l && r <= t){
            tr[p].tag ^= 1;
            swap(tr[p].tag0, tr[p].tag1);
            tr[p].cnt = tr[p].len - tr[p].cnt;
            return ;
        }
        down(p);
        int mid = (l + r) >> 1;
        if (s <= mid)
            modify(p << 1, l, mid, s, t);
        if (t > mid)
            modify(p << 1 | 1, mid + 1, r, s, t);
        pushup(p);
    }
    int query(int p, int l, int r, int s, int t){
        if (s <= l && r <= t){
            return tr[p].sum;
        }
        down(p);
        int mid = (l + r) >> 1;
        int res = 0;
        if (s <= mid)
            res += query(p << 1, l, mid, s, t);
        if (t > mid)
            res += query(p << 1 | 1, mid + 1, r, s, t);
        return res; 
    }
}T;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
        lst[i] = buc[a[i]];
        buc[a[i]] = i;
    }
    cin >> m;
    for (int i = 1; i <= m; i++){
        cin >> inp[i].l >> inp[i].r;
        inp[i].id = i;
        pos[inp[i].r].push_back(i);
    }
    T.build(1, 1, n);
    for (int i = 1; i <= n; i++){
        T.modify(1, 1, n, lst[i] + 1, i);
        T.add(1, 0, 1);
        for (auto v : pos[i]){
            ans[inp[v].id] = T.query(1, 1, n, inp[v].l, i);
        }
    }
    for (int i = 1; i <= m; i++){
        cout << ans[i] << '\n';
    }
}
相关推荐
颜酱10 小时前
图的数据结构:从「多叉树」到存储与遍历
javascript·后端·算法
saltymilk15 小时前
使用 C++ 模拟 ShaderLanguage 的 swizzle
c++·模板元编程
zone773916 小时前
006:RAG 入门-面试官问你,RAG 为什么要切块?
后端·算法·面试
CoovallyAIHub18 小时前
OpenClaw 近 2000 个 Skills,为什么没有一个好用的视觉检测工具?
深度学习·算法·计算机视觉
CoovallyAIHub18 小时前
CVPR 2026 | 用一句话告诉 AI 分割什么——MedCLIPSeg 让医学图像分割不再需要海量标注
深度学习·算法·计算机视觉
CoovallyAIHub19 小时前
Claude Code 突然变成了 66 个专家?这个 5.8k Star 的开源项目,让我重新理解了什么叫"会用 AI"
深度学习·算法·计算机视觉
兆子龙19 小时前
前端哨兵模式(Sentinel Pattern):优雅实现无限滚动加载
前端·javascript·算法
xlp666hub1 天前
Leetcode第五题:用C++解决盛最多水的容器问题
linux·c++·leetcode
CoovallyAIHub1 天前
9个视觉语言模型工厂实测:Qwen 87.9%碾压全场,你的显卡能跑哪个?
算法
SparkX开源AI知识库1 天前
手摸手带你安装OpenClaw并对接飞书
算法·架构