1 条题解
-
0
自动搬运
来自洛谷,原作者为

是青白呀
咕咕咕?咕咕咕!搬运于
2025-08-24 23:04:09,当前版本为作者最后更新于2024-11-07 22:18:25,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
考虑如何确定一个保留方案合法。假设保留的下标序列为 ,则对于任意 ,位于 内的所有字符都需要能够删除得只剩 。于是直接考虑对于一个区间 ,考察它能否被删除到只剩 。我们可以倒着扫描整个区间,使用一个栈维护目前还未被删除的字符。对于当前进入的一个字符 ,不断弹出栈顶的字符直到栈顶字符不能被 删除,然后把 压入栈。若最后栈中只有 处的一个字符,则该区间合法。
考虑第一个段,不难发现第一个位置的字符是一定会被保留的。枚举最靠后的一个被这个字删除的位置 ,则存在一种合法方案是先处理完 的所有字符,然后再利用 删除 的所有字符。不难发现这实际上是将一个 的问题递归到了一个 的问题。不妨设 表示 的答案,也即从 开始执行操作得到的最小字典序,提前预处理每个区间是否能被删除得只剩第一个,枚举即可做到 。
考虑去除无效的转移点。对于一个加入栈的元素序列,若取出其后缀进行操作,不难发现这部分元素的压入弹出操作与原先一致。因此可以直接对 执行上述流程,设 表示被 删除的所有位置集合,则所有 中的转移点都是合法的,同时根据上述结论,我们发现任取后缀的情况下,其他点也不会被 删除,故不存在 以外的有效转移点。不难发现 大小的总和是 的,于是转移复杂度正确。
具体地,我们设 表示以 作为首个保留的位置时,最小字典序的下一个保留位置; 表示以 作为首个保留位置的最小字典序,求 时,找到所有 ,并比较 的字典序,选取最小的那一个(这是因为 实际上是会被删除的, 的下一个字符实际上在位置 )接在 的字符之后作为 即可。注意到 存在拼合关系,故我们可以使用字符串哈希,并倍增找到两个串首个不同位置的方式,以此在 的复杂度内比较两个串的字典序,只需将 改为倍增数组存储哈希值即可。
最终总复杂度为 ,瓶颈在每个转移处 比较字典序。代码实现中使用了双哈希。
#include<bits/stdc++.h> #define rep(i,j,k) for(int i=j;i<=k;i++) #define repp(i,j,k) for(int i=j;i>=k;i--) #define ls(x) (x<<1) #define rs(x) ((x<<1)|1) #define mp make_pair #define sec second #define fir first #define pii pair<int,int> #define lowbit(i) i&-i #define double long double #define int long long #define qingbai 666 using namespace std; typedef long long ll; typedef unsigned long long ull; const int N=5e5+5,M=30,S=(1<<8)+5,inf=1e9+7; const double eps=1e-8; void read(int &p){ int x=0,w=1; char ch=0; while(!isdigit(ch)){ if(ch=='-')w=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<1)+(x<<3)+ch-'0'; ch=getchar(); } p=x*w; } int m,n,a[N]; bool del[M][M]; struct hash{ int base,mo,bs[N]; void init(int x,int y){ base=x,mo=y; bs[0]=1; rep(i,1,n) bs[i]=bs[i-1]*base%mo; } int merge(int llen,int lv,int rv){ return (lv*bs[llen]+rv)%mo; } }H[2]; int f[N][20]; struct node{ int len,v[2]; friend node operator+(node x,node y){ node res; res.len=x.len+y.len; rep(i,0,1) res.v[i]=H[i].merge(x.len,x.v[i],y.v[i]); return res; } friend bool operator==(node x,node y){ return x.len==y.len&&x.v[0]==y.v[0]&&x.v[1]==y.v[1]; } }g[N][20]; int getmin(int x,int y){ int sx=x,sy=y; repp(i,19,0) if(g[x][i]==g[y][i])x=f[x][i],y=f[y][i]; if(x>n)return sx; if(y>n)return sy; if(a[x]<a[y])return sx; else return sy; } signed main(){ read(m),read(n); rep(i,1,m){ string s; cin>>s; rep(j,1,m) del[i][j]=(s[j-1]=='1'); } string s; cin>>s; rep(i,1,n) a[i]=s[i-1]-'a'+1; rep(i,0,19) g[n+1][i]=(node){0,{0,0}},f[n+1][i]=n+1; H[0].init(19491001,620071201),H[1].init(19260817,998244853); stack<int>stk; repp(i,n,1){ f[i][0]=i+1; while(!stk.empty()&&del[a[i]][a[stk.top()]]) f[i][0]=getmin(f[i][0],f[stk.top()][0]),stk.pop(); stk.push(i); g[i][0]=(node){1,{a[i],a[i]}}; rep(j,1,19){ f[i][j]=f[f[i][j-1]][j-1]; g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1]; } } for(int i=1;i<=n;i=f[i][0]) printf("%c",a[i]-1+'a'); return 0; }
- 1
信息
- ID
- 8970
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者