CF1654B 做题历程
每次删前缀,容易想到从后往前做,随便手模了一下,写出了如下代码:
int T=read();
while(T--){
scanf("%s",s+1);
int n=strlen(s+1);
memset(vis,0,sizeof(vis));
for(int i=n;i;--i)
if(vis[s[i]-'a']){
for(int j=i+1;j<=n;++j)
putchar(s[j]);
puts("");
break;
}else vis[s[i]-'a']=1;
}
哈哈,发现过不了样例最后一个 case,发现可能前面就会被卡住,不一定是要最后一个后缀中只出现过一次的点
哈哈,然后没有细想怎么解决这个问题,直接放弃了从后往前做的思路,看到 2e5 给了 2s,开始考虑根号分治之类的
发现如果串长小的话可以直接 Z 函数 乱糊,可是串长大了还是不会
考虑 nlogn 算法,考虑能不能直接二分出最后停住的位置
思考了一下,发现好像没有单调性,G
然后考虑如何优化这个暴力匹配的过程
发现每一次其实在求固定一个后缀,找从它后面开始的后缀中与之最大的 lcp,直接上一个 SA,考虑我 height 数组是在干什么
假如我不管“从后面开始”这个限制,我直接 即可
假设现在我已经删到了位置 ,我把 ,那么我在 数组上直接从 往右扫,扫到第一个不是 的位置就好了
同理可以从 往左扫,取第一个是因为我 lcp 显然是单调递减的
这样直接干一共是 的,我考虑线段树优化一下这个找第一个不是 的位置的过程
我直接线段树维护一下 height 最小值,二分一下即可。
每个点的 height 只会被标为 一次,所以复杂度是对的
然后写出了如下代码:
#include<bits/stdc++.h>
#define mid ((l+r)>>1)
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
const int N = 2e5+5;
// char buf[1<<23],*p1=buf,*p2=buf;
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read(){
int s=0,w=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
return s*w;
}
struct Tree{int cv,mn;}t[N<<2];
int rk[N],sa[N],tax[N],tmp[N],height[N];
char s[N];
int n,m,T;
void radix_sort(){
for(int i=1;i<=m;i++)tax[i]=0;
for(int i=1;i<=n;i++)tax[rk[i]]++;
for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
for(int i=n;i>=1;i--)sa[tax[rk[tmp[i]]]--]=tmp[i];
}
void suffix_sort(){
m=200;
for(int i=1;i<=n;i++)
rk[i]=s[i]-'a'+1,tmp[i]=i;
radix_sort();
for(int w=1,p=0;p<n;m=p,w<<=1){
p=0;
for(int i=1;i<=w;i++)tmp[++p]=n-w+i;
for(int i=1;i<=n;i++)if(sa[i]>w)tmp[++p]=sa[i]-w;
radix_sort(),swap(tmp,rk);
rk[sa[1]]=p=1;
for(int i=2;i<=n;i++)
rk[sa[i]]=(tmp[sa[i-1]]==tmp[sa[i]]&&tmp[sa[i-1]+w]==tmp[sa[i]+w])?p:++p;
}
}
void get_height() {
int k=0;
for(int i=1;i<=n;i++) {
if(k)k--;
int j=sa[rk[i]-1];
while(s[i+k]==s[j+k])k++;
height[rk[i]]=k;
}
}
void pushup(int rt){t[rt].mn=min(t[ls].mn,t[rs].mn);}
void pushdown(int rt){if(t[rt].cv)t[ls].cv=t[rs].cv=1,t[ls].mn=t[rs].mn=1e9,t[rt].cv=0;}
void build(int l,int r,int rt){
if(l==r)return t[rt].mn=height[l],void(); pushdown(rt);
build(l,mid,ls),build(mid+1,r,rs),pushup(rt);
}
void alter(int l,int r,int rt,int id){
if(l==r)return t[rt].mn=1e9,void(); pushdown(rt);
id<=mid?alter(l,mid,ls,id):alter(mid+1,r,rs,id);
pushup(rt);
}
int query(int l,int r,int rt,int L,int R){
if(L<=l&&r<=R)return t[rt].mn; pushdown(rt);
if(R<=mid)return query(l,mid,ls,L,R);
if(mid<L)return query(mid+1,r,rs,L,R);
return min(query(l,mid,ls,L,R),query(mid+1,r,rs,L,R));
}
signed main(){
T=read();
while(T--){
scanf("%s",s+1),n=strlen(s+1);
suffix_sort(),get_height(),build(1,n,1);
int now=1,v;
while(1){
int l=rk[now]+1,r=n,len=0;
// cout<<"now:"<<now<<" "<<rk[now]<<endl;
// for(int i=1;i<=n;++i){
// int t=query(1,n,1,i,rk[i]);
// if(t==1e9)cout<<-1<<" ";
// else cout<<t<<" ";
// }puts("");
while(l<=r){
int midd=(l+r)>>1,tp=query(1,n,1,rk[now]+1,midd);
if(tp!=1e9)len=max(len,tp),r=midd-1;
else l=midd+1;
}
l=1,r=rk[now];
while(l<=r){
int midd=(l+r)>>1,tp=query(1,n,1,midd,rk[now]);
if(tp!=1e9)len=max(len,tp),l=midd+1;
else r=midd-1;
}
if(len==0)break;
// cout<<len<<endl;
for(int i=now;i<=now+len-1;++i)
alter(1,n,1,rk[i]);
now+=len;
}
for(int i=now;i<=n;++i)putchar(s[i]);
puts("");
t[1].cv=1;
}
return 0;
}
然后一通调试,就是不知道怎么错了,一共搞了 2h+
心态有点炸了,看了一眼榜,哈哈,人均会 ABCD
开始看后面的题,时间太仓促,每道题都只是扫完题面,发现第一眼没有好想法,走人
滚回来想 T2,看到榜上全是 4 分钟切掉的,意识到这道题应该是一道签到题,我搞复杂了
开始按 Ctrl+Z,又重拾最开始的思路,开始倒着想
想了 2min,哈哈,会了,花了 1min 敲代码,哈哈,过了
T=read();
while(T--){
memset(vis,0,sizeof(vis));
scanf("%s",s+1);
n=strlen(s+1),p=n;
for(int i=n;i;--i){
if(!vis[s[i]-'a'])p=i;
vis[s[i]-'a']=1;
}
for(int i=p;i<=n;++i)
putchar(s[i]);
puts("");
}
这时候已经无心思考 C 了,摆着 T3 的题面,大脑乱掉了,GG
所以反思一下失误在哪里,为啥会花这么多时间写了一坨 rubbish
然后没有细想怎么解决这个问题,直接放弃了从后往前做的思路
主观地来说,是这个 sb 凭感觉做题,毛毛躁躁,抓住一半就跑
客观上,明明一道 的题,不是很懂为啥给了 2e5 2s
哈哈,掉大分,哈哈
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具