「题解」Luogu3514 [POI2011]LIZ-Lollipop

题目链接:Luogu3514 [POI2011]LIZ-Lollipop

#题意简述

给定一个长度为 n(n106) 的仅由 1,2 组成的序列,q(q106) 次询问,每次询问是否存在一个子串使得子串和为 k,不存在输出 NIE,否则输出任意一个可行的区间左右端点。

#大致思路

首先,观察到询问次数较多,需要考虑将所有可能组成的值的区间全部处理出来,由于所有可能的值的数量较大,于是需要考虑通过寻找所有可能的值的区间之间的关系进行递推。

假设我们已知 k 的表示区间,考虑将该区间进行微量的改动可能造成的影响。考虑到添加只是删除操作的逆操作,且需要考虑的边界问题较少,于是这里讨论删除操作。假设当前边界两端都是 1,显然可以得到 k1k2 的区间;假设当前边界的两端为 12,那么可以得到 k1k2 的区间;如果两边都是 2,那么只能得到 k2 的区间。

综上,我们发现,如果 k(k>2) 能够被组成,那么 k2 一定可以被组成,只需要删除至多两个位置即可。

于是,我们只需要找到最大的可表示的奇数与最大的可表示的偶数即可,显然是一个前缀或后缀的形式。

const int N = 2000010;
const int INF = 0x3f3f3f3f;

template <typename T> inline void read(T &x) {
    x = 0; int f = 1; char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
    x *= f;
}

int n, q, sum[N], a[N], mx[2], l[N], r[N]; char c[N];

inline void update(int x, int lp, int rp) {
    if (mx[x & 1] < x) mx[x & 1] = x, l[x] = lp, r[x] = rp;
}

inline void get_pos(int x) {
    if (a[l[x + 2]] == 1 && a[r[x + 2]] == 1)
      l[x] = l[x + 2] + 1, r[x] = r[x + 2] - 1;
    else if (a[l[x + 2]] == 2)
      l[x] = l[x + 2] + 1, r[x] = r[x + 2];
    else l[x] = l[x + 2], r[x] = r[x + 2] - 1;
}

int main() {
    read(n), read(q); scanf("%s", c + 1);
    for (int i = 1; i <= n; ++ i) a[i] = c[i] == 'T' ? 2 : 1;
    for (int i = 1; i <= n; ++ i) sum[i] = sum[i - 1] + a[i];
    for (int i = n; i >= 1; -- i) update(sum[i], 1, i);
    for (int i = 1; i <= n; ++ i) update(sum[n] - sum[i - 1], i, n);
    for (int i = mx[1] - 2; i > 0; i -= 2) get_pos(i);
    for (int i = mx[0] - 2; i > 0; i -= 2) get_pos(i);
    while (q --) {
        int x = 0; read(x);
        if (x > mx[x & 1]) printf("NIE\n");
        else printf("%d %d\n", l[x], r[x]);
    }
    return (0 - 0);
}

posted @   Dfkuaid  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2021-03-02 [DP浅析]线性DP初步 - 0
点击右上角即可分享
微信分享提示