冲刺NOIP2024专题之字符串专题
冲刺NOIP2024专题之字符串专题
Security
Yet Another LCP Problem
String Distance
观察这个定义,我们发现
且
我们发现只有当一个串内有一个极大不降子串(即这个不降子串不能向前后扩展),且除了这部分之外两个串都一样,
我们发现这个玩意相当于枚举出每个极大不降子串之后找除了这一段之外与它的前后缀都相等的串,前缀好说,排序之后暴力跑
后缀怎么办呢?它相当于翻转串的前缀,我们发现这玩意
最后提醒一句,多测不清空,爆零两行泪
最坏复杂度 xrlong
貌似有建两棵
CODE
#include<bits/stdc++.h>
using namespace std;
#define N 200100
#define lowbit(a) a&(-a)
long long n,siz,last=1,ans;
char in[N];
vector <long long> s[N],us[N],d1[N],d2[N],d3[N],t(2*N),lcp(N);
struct TRIE
{
long long sizt=0,nxt[N][26],lar[N],inn[N],ss=0;
void del(int now)
{
lar[now]=inn[now]=0;
for(int i=0;i<=25;i++)
if(nxt[now][i]!=0)
del(nxt[now][i]),nxt[now][i]=0;
}
void clear()
{
del(0);
sizt=ss=0;
}
void in(int pl,int x)
{
for(int i=pl;i<=ss;i+=lowbit(i))
t[i]+=x;
}
long long check(int st,int ed)
{
long long sum1=0,sum2=0;
for(int i=ed;i>=1;i-=lowbit(i))
sum1+=t[i];
for(int i=st-1;i>=1;i-=lowbit(i))
sum2+=t[i];
return sum1-sum2;
}
void insert(const vector<long long> &ins,vector<long long> &rec)
{
long long now=0;
for(int i=siz;i>=1;i--)
{
if(nxt[now][ins[i]-'a']!=0)
now=nxt[now][ins[i]-'a'];
else
nxt[now][ins[i]-'a']=++sizt,now=sizt;
rec[i]=now;
}
}
void dfs(int now)
{
inn[now]=++ss;
lar[now]=1;
for(int i=0;i<=25;i++)
if(nxt[now][i]!=0)
{
dfs(nxt[now][i]);
lar[now]+=lar[nxt[now][i]];
}
}
long long find(long long node){return check(inn[node],inn[node]+lar[node]-1);}
}tree;
bool judge(const vector<long long> &cmp1,const vector<long long> &cmp2)
{
for(int i=1;i<=siz;i++)
if(cmp1[i]!=cmp2[i])
return false;
return true;
}
void solve(int beg,int end)
{
ans+=(end-beg+1)*(n-end)*1337;
long long size=0,tot=0;int now=0;tree.clear();
for(int i=beg;i<=end;i++)
d1[++size]=s[us[i][siz+1]];
vector<long long>().swap(lcp);
lcp.resize(size+1);
for(int i=1;i<=size;i++) vector<long long>().swap(d2[i]),vector<long long>().swap(d3[i]),d2[i].resize(siz+3),d3[i].resize(siz+3);
sort(d1+1,d1+size+1);
for(int i=1;i<=size;i++)
{
for(int j=siz,nxt=siz;j>=1;j--)
{
if(d1[i][j]>d1[i][j+1]) nxt=j;
d3[i][j]=nxt;
}
d3[i][0]=d3[i][1];
}
for(int i=2;i<=size;i++)
for(int j=1;j<=siz;j++)
if(d1[i-1][j]==d1[i][j]) lcp[i]=j;
else break;
for(int i=1;i<=size;i++) tree.insert(d1[i],d2[i]);
tree.dfs(0);
for(int i=0;i<=siz;i++)
{
now=0;
for(int j=1;j<=size;j++)
{
if(now>=j) tree.in(tree.inn[d2[j][1]],-1);
now=max(now,j);
while(now+1<=size&&lcp[now+1]>=i-1) now++,tree.in(tree.inn[d2[now][1]],1);
if(i==0||d1[j][i]<d1[j][i-1])
{
if(d3[j][i]+1<=siz)
tot+=tree.find(d2[j][d3[j][i]+1]);
else
tot+=tree.find(0);
}
}
}
ans+=size*(size-1)-tot;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
cin>>(in+1);
siz=strlen(in+1);
s[i].push_back(0);
for(int j=1;j<=siz;j++) s[i].push_back(in[j]);
s[i].push_back(i);
}
for(int i=1;i<=n;i++) us[i]=s[i];
for(int i=1;i<=n;i++) sort(us[i].begin(),us[i].end()-1);
sort(us+1,us+n+1);
for(int i=1;i<n;i++)
if(!judge(us[i],us[i+1]))
solve(last,i),last=i+1;
solve(last,n);
printf("%lld\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架