「题解」Luogu3514 [POI2011]LIZ-Lollipop
#题意简述
给定一个长度为 的仅由 组成的序列, 次询问,每次询问是否存在一个子串使得子串和为 ,不存在输出 NIE
,否则输出任意一个可行的区间左右端点。
#大致思路
首先,观察到询问次数较多,需要考虑将所有可能组成的值的区间全部处理出来,由于所有可能的值的数量较大,于是需要考虑通过寻找所有可能的值的区间之间的关系进行递推。
假设我们已知 的表示区间,考虑将该区间进行微量的改动可能造成的影响。考虑到添加只是删除操作的逆操作,且需要考虑的边界问题较少,于是这里讨论删除操作。假设当前边界两端都是 ,显然可以得到 和 的区间;假设当前边界的两端为 和 ,那么可以得到 和 的区间;如果两边都是 ,那么只能得到 的区间。
综上,我们发现,如果 能够被组成,那么 一定可以被组成,只需要删除至多两个位置即可。
于是,我们只需要找到最大的可表示的奇数与最大的可表示的偶数即可,显然是一个前缀或后缀的形式。
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);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2021-03-02 [DP浅析]线性DP初步 - 0