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';
    }
}
相关推荐
浅念-2 小时前
C++ string类
开发语言·c++·经验分享·笔记·学习
寻星探路3 小时前
【前端基础】HTML + CSS + JavaScript 快速入门(三):JS 与 jQuery 实战
java·前端·javascript·css·c++·ai·html
你的冰西瓜4 小时前
2026春晚魔术揭秘——变魔法为物理
算法
忘梓.4 小时前
解锁动态规划的奥秘:从零到精通的创新思维解析(10)
c++·算法·动态规划·代理模式
foolish..4 小时前
动态规划笔记
笔记·算法·动态规划
消失的dk4 小时前
算法---动态规划
算法·动态规划
羑悻的小杀马特4 小时前
【动态规划篇】欣赏概率论与镜像法融合下,别出心裁探索解答括号序列问题
c++·算法·蓝桥杯·动态规划·镜像·洛谷·空隙法
绍兴贝贝4 小时前
代码随想录算法训练营第四十六天|LC647.回文子串|LC516.最长回文子序列|动态规划总结
数据结构·人工智能·python·算法·动态规划·力扣
愚润求学4 小时前
【动态规划】二维的背包问题、似包非包、卡特兰数
c++·算法·leetcode·动态规划