首页 > 其他分享 >[ARC058F] Iroha Loves Strings

[ARC058F] Iroha Loves Strings

时间:2024-03-29 22:00:29浏览次数:15  
标签:字符 aligned sum 最小 字符串 ARC058F Iroha include Strings

题意

给定 \(n\) 个字符串 \(s_1, s_2, ..., s_n\)。

你需要在其中选择一些字符串,按照顺序拼接。

在所有生成的长度为 \(k\) 的字符串中,选择字典序最小的一个。

\(n \le 2000, k \le 10 ^ 4, \sum |s_i| \le 10 ^ 6\)

Sol

考虑一个朴素的 dp。

设 \(f_{i, j}\) 表示前 \(i\) 个字符串,放到了前 \(j\) 个位置的最小的字符串。

这个 dp 的复杂度为 \(nk \times \sum |s_i|\)。

不难注意到一个事情,如果当前放的字符串 \(s_i\) 已经不是最优的字典序了,那么无论后面怎么放,此处放 \(s_i\) 都不可能成为最优方案。

考虑想的暴力一点:

设 \(f_{i, j, k}\) 表示用第 \(j\) 个字符串的第 \(k\) 位填在第 \(i\) 位,是否可以为当前字典序最小的方案,且合法。

先考虑简单的合法,每次新放一个字符串都需要判断放当前字符串是否可以组成长度为 \(k\) 的答案。

设 \(g_{i, j}\) 表示用第 \(j\) 个字符串填完前 \(i\) 位是否能合法。

显然:

\[\forall k \in [j + 1, n], g_{i, j} = g_{i, j} \vee g_{i + len_j, k} \]

\(g_{i, j}\) 显然可以在 \(O(nk)\) 的时间求出。

考虑当前的最小字符。

注意到当前可以填的最小字符 \(s_{j, k}\) 满足:

\[\left\{ \begin{aligned} & \min_{j, k} s_{j, k + 1} , & & [f_{i - 1, j, k} = 1] \\ & \min_{j} s_{j, 1} , & & [\exists k, k < j, f_{i - 1, k, len_k} = 1] & \end{aligned} \right. \]

注意到下面的式子和 \(g\) 类似,可以在 \(O(nk)\) 之内找出最小字符 \(c\)。

考虑上面的式子。

考虑直接把 \(j, k\) 两维暴力压成一维后用 \(\text{bitset}\) 维护。

二分当前的最小字符 \(c\),考虑预处理 \(h_{i, j}\) 表示第 \(j\) 个位置存在字典序小于等于 \(i\) 字符。

那么一个很显然的事情,当前最小字符为 \(c\) 合法,当且仅当 (h[c] & (f[i - 1] << 1)) 的 \(\text{bitset}\) 存在 \(1\)。

考虑二分 \(c\),复杂度:\(O(\frac{n \times \sum |s_i|}{\omega} \times \log 26)\)。

那么转移就很简单了。

\[\left\{ \begin{aligned} f_{i, j, k} \to f_{i + 1, j, k + 1}, & & s_{j, k + 1} = c \\ f_{i, j, len_j} \to f_{i + 1, k, 1}, & & s_{k, 1} = c, g_{i + 1, k} = 1 \\ \end{aligned} \right. \]

实现细节较多。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <string>
#include <bitset>
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;
}
string read_() {
    string ans;
    char c = getchar();
    while (c < 'a' || c > 'z') c = getchar();
    while (c >= 'a' && c <= 'z') ans += c, c = getchar();
    return ans;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

const int N = 2e3 + 5, M = 1e6 + 5, K = 1e4 + 5;

array <int, N> len, fir, sum;

array <bitset <N>, K> g, suf;
array <bitset <M>, 27> h;
array <bitset <M>, 2> f;

bitset <M> pre, vis;

bool check(int v, int c) { return (h[c] & (f[v] << 1)).count(); }

bool _edmer;
int main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
/* #ifdef cxqghzj */
    /* freopen("_.txt", "r", stdin); */
/* #endif */
    int n = read(), m = read();
    string mp;
    /* write(f[0].count()), puts("#"); */
    for (int i = 1; i <= n; i++)
        vis[fir[i] = mp.size()] = 1, mp += read_(), len[i] = (sum[i] = mp.size()) - fir[i];
    for (int i = 1; i <= 26; i++)
        for (int j = 0; j < (int)mp.size(); j++)
            if (!vis[j])
                h[i][j + 1] = (mp[j] <= ('a' + i - 1));
    suf[m + 1][n + 1] = 1;
#define upd(x, y) (x = x | y)
    for (int j = n; j; j--) {
        for (int i = 1; i + len[j] - 1 <= m; i++)
            upd(g[i][j], suf[i + len[j]][j + 1]);
        for (int i = 1; i <= m + 1; i++) suf[i][j] = g[i][j] | suf[i][j + 1];
    }
    f[0][0] = 1, pre[1] = 1;
    int v = 0;
    string ans;
    for (int i = 0; i < m; i++) {
        int l = 1, r = 26;
        for (int j = 1; j <= n; j++) {
            if (pre[j] && g[i + 1][j]) r = min(r, mp[fir[j]] - 'a' + 1);
            pre[j + 1] = f[v][sum[j]] | pre[j];
        }
        pre = 0;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (check(v, mid)) r = mid;
            else l = mid + 1;
        }
        ans.push_back(r + 'a' - 1);
        f[v ^ 1] = h[r] & (f[v] << 1);
        bool flg = 0;
        for (int j = 0; j <= n; j++) {
            if (j && g[i + 1][j] && mp[fir[j]] <= r + 'a' - 1)
                upd(f[v ^ 1][fir[j] + 1], flg);
            flg |= f[v][sum[j]];
        }
        /* write(f[v ^ 1].count()), puts(""); */
        v ^= 1;
    }
    printf("%s\n", ans.c_str());
    return 0;
}

标签:字符,aligned,sum,最小,字符串,ARC058F,Iroha,include,Strings
From: https://www.cnblogs.com/cxqghzj/p/18104697

相关文章

  • H. Impartial Strings
    H.ImpartialStringsProblem-H-Codeforces抽象场不传题解......
  • CF1930D1 - Sum over all Substrings (Easy Version)
    对于每一个\(f(i,j)\),我们考虑如何计算。我们发现,\(\texttt{1010}\)式的字符串很有用,所以这启发我们如果遇到了一个模式\(p_i=\texttt{'1'}\),那么我们可以在\(i+1\)的位置放一个\(\texttt{'1'}\)。这样我们直接处理了\(i,i+1,i+2\)。容易证明这是最优的。#incl......
  • UVA10829 L-Gap Substrings
    我永远喜欢数据结构。貌似是此题中第一个使用SA+分治+二维数点做法的题解?题目传送门给出字符串\(s\)和常数\(g\),求出有多少四元组\((l_1,r_1,l_2,r_2)\),满足\(s[l_1,r_1]=s[l_2,r_2]\)且\(r_1+g+1=l_2\)。\(T\)组数据,\(1\leT,g\le10\),\(|s|\le5\times10......
  • 标准库之strings
    目录一、strings库介绍二、字符串比较-Compare1.介绍2.示例三、检测字符串是否包含子串-Contains1.介绍2.示例四、大小写转换1.介绍2.示例五、统计子字符串出现的次数1.介绍2.示例六、判断字符串的前后缀1.介绍2.示例七、分割和连接1.介绍2.示例八、索引1.介绍2.示......
  • AT_abc343_g [ABC343G] Compress Strings 题解
    题目传送门前置知识前缀函数与KMP算法|状压DP解法由于\(\sum\limits_{i=1}^{n}|S_{i}|\)极大且不需要记录路径,所以luoguP2322[HNOI2006]最短母串问题的枚举所有可能的字符串\(T\)进行判断不可做。设\(f_{i,j}\)表示当“字符串包含状态”对应的二进制数为\(......
  • AT_abc343_G [ABC343G] Compress Strings 题解
    分析水题,评分能有$2100$可能是因为很多人卡E了。我说真的,E好难啊。$n$只有$20$,考虑从状压的角度入手。定义状态函数$f_{s,i}$表示当某个字符串$T$包含了所有$s$的二进制中为$1$的下标$S_j$且$T$末尾包含的子串为$S_i$时$T$的最小长度。那很显然的就有转......
  • Sofia and Strings(字符串,思维)
    SofiaandStrings题面\(t\)组数据。每一次测试,有长度为\(n\)的序列\(s\),长度为\(m\)的序列\(t\)。你可以对\(s\)进行两种操作:删除\(s_i,1\lei\le|s|\)(\(s\)从\(1\)开始标号).将\(s_l,s_{l+1},\dots,s_r\)排序(\(1\lel\ler\le|s|\))。上面\(|s|\)......
  • ABC343 G Compress Strings 题解
    QuestionABC343GCompressStrings给定\(N\)个字符串\(S_1,S_2,\cdots,S_N\)找到一个包含所有这些字符串作为子字符串的最小长度的字符串一个字符串\(S\)包含一个字符串\(T\)作为子字符串是指:如果\(T\)可以通过从\(S\)的开头删除零个或多个字符以及从末尾删除......
  • Collapsing Strings
    做这道题目的时候学CDQ和整体二分学成傻逼了是吧?我寻思着非要把一整个数组传进去操作,明明一个一个考虑不就好了真的烦躁题外话,做这道题目的时候,探索出来一个东西,vector要放字符串的话,template可以写char*最开始的想法是编写一个函数work(vector<char*>a,vector<char*>b),然......
  • Codeforces 1830C Hyperregular Bracket Strings
    考虑到区间的限制\([l,r]\)就是要求\([l,r]\)里的字符会在\([l,r]\)里找到匹配。假设还有个区间\([l',r']\)满足\(l\lel'\ler\ler'\),能够发现限制变成了\([l,l'),[l',r],(r,r']\)这\(3\)个区间内的字符能在对应区间内找到匹配。继续,假设\(l\lel'\le......