YC322A [ 20240724 CQYC NOIP 模拟赛 T3 ] 小 M 的字符串(string)

cxqghzj·2024-07-24 15:18·4 次阅读

YC322A [ 20240724 CQYC NOIP 模拟赛 T3 ] 小 M 的字符串(string)

题意#

给定一个 0/1 字符串,你需要从中选出尽可能多的不相交的子串使得按顺序字典序单调递增。

n25000

Sol#

先考虑能最多选出多少个不相交的子串,这个是 nlogn,但是这个没用。

考察一下子串的长度,由于字典序的限制,最劣的情况下就是一个子串比上一个子串正好多了一位。

所以子串的长度最大是 2n 的,这个是有用的。

直接暴力排序很菜,是 O(n×n×nlogn) 的,等于没这个性质。

想象一下可以想到直接扔到 Trie 上面插进去,然后 dfs 暴力跑一遍就可以保证字典序的单调递增了。

然后接着整一个 dp 就完事了,发现这个玩意有个前缀转移很唐,考虑直接把下标当成子串的数量,这样每次枚举到的子串 [l,r] 就可以直接转移最大的 dpk<l 的位置,容易发现这就是对的,直接 lower_bound 就做完了。

时间复杂度 O(nnlogn)

Code#

Copy
#include <iostream> #include <algorithm> #include <cstdio> #include <array> #include <vector> #define pii pair <int, int> using namespace std; #ifdef ONLINE_JUDGE // #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) // char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf; #endif int read() { int p = 0, flg = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-' )flg = -1; c = getchar(); } while (c >= '0' && c <= '9') { p = p * 10 + c - '0'; c = getchar(); } return p * flg; } void write(int x) { if (x < 0) { x = -x; putchar('-'); } if (x > 9) { write(x / 10); } putchar(x % 10 + '0'); } bool _stmer; #define fi first #define se second const int N = 2.5e4 + 5, M = 405; char strbuf[N]; string s; array <array <int, 2>, N * M> nex; array <vector <pii>, N * M> isl; int cnt; array <int, N> f; int tot; void dfs(int x) { sort(isl[x].begin(), isl[x].end(), greater <pii>()); for (auto k : isl[x]) { int pos = lower_bound(f.begin(), f.begin() + 1 + tot, k.fi) - f.begin() - 1; f[pos + 1] = min(f[pos + 1], k.se); if (pos == tot) tot++; } if (nex[x][0]) dfs(nex[x][0]); if (nex[x][1]) dfs(nex[x][1]); } bool _edmer; int main() { cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n"; #ifndef cxqghzj // freopen("string.in", "r", stdin); // freopen("string.out", "w", stdout); #endif int n = read(); scanf("%s", strbuf); s = strbuf, s = " " + s; f.fill(n + 1), f[0] = 0; int m = 405; for (int i = 1; i <= n; i++) { int p = 0; for (int j = i; j <= n && j - i + 1 <= m; j++) { if (!nex[p][s[j] - '0']) cnt++, nex[p][s[j] - '0'] = cnt; p = nex[p][s[j] - '0']; isl[p].push_back(make_pair(i, j)); } } dfs(0); write(tot), puts(""); return 0; }
posted @   cxqghzj  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示
目录