4.字符串
字符串
开题顺序:
QOJ 8079.Range Periodicity Query
-
设第
次操作后的字符串为 。注意到若 不是 的周期则 一定不是 的周期。 -
对于每个
作为周期的时间都是一段区间。由 luogu P3435 [POI2006] OKR-Periods of Words 结论,得到 有长度为 的 border$ 等价于 有长度为 的周期。可以使用二分哈希辅助判断。 -
询问转化为二维偏序问题,扫描线加线段树单点修改区间查询维护。
-
在 Gym 上会莫名
,加个超级快读就过了。点击查看代码
namespace IO{ #ifdef LOCAL FILE*Fin(fopen("test.in","r")),*Fout(fopen("test.out","w")); #else FILE*Fin(stdin),*Fout(stdout); #endif class qistream{static const size_t SIZE=1<<16,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qistream(FILE*_fp=stdin):fp(_fp),p(0){fread(buf+p,1,SIZE-p,fp);}void flush(){memmove(buf,buf+p,SIZE-p),fread(buf+SIZE-p,1,p,fp),p=0;}qistream&operator>>(char&x){x=getch();while(isspace(x))x=getch();return*this;}template<class T>qistream&operator>>(T&x){x=0;p+BLOCK>=SIZE?flush():void();bool flag=false;for(;!isdigit(buf[p]);++p)flag=buf[p]=='-';for(;isdigit(buf[p]);++p)x=x*10+buf[p]-'0';x=flag?-x:x;return*this;}char getch(){p+BLOCK>=SIZE?flush():void();return buf[p++];}qistream&operator>>(char*str){char ch=getch();while(ch<=' ')ch=getch();int i=0;for(;ch>' ';++i,ch=getch())str[i]=ch;str[i]='\0';return*this;}}qcin(Fin); class qostream{static const size_t SIZE=1<<16,BLOCK=64;FILE*fp;char buf[SIZE];int p;public:qostream(FILE*_fp=stdout):fp(_fp),p(0){}~qostream(){fwrite(buf,1,p,fp);}void flush(){fwrite(buf,1,p,fp),p=0;}template<class T>qostream&operator<<(T x){int len=0;p+BLOCK>=SIZE?flush():void();x<0?(x=-x,buf[p++]='-'):0;do buf[p+len]=x%10+'0',x/=10,++len;while(x);for(int i=0,j=len-1;i<j;++i,--j)std::swap(buf[p+i],buf[p+j]);p+=len;return*this;}qostream&operator<<(char x){putch(x);return*this;}void putch(char ch){p+BLOCK>=SIZE?flush():void();buf[p++]=ch;}qostream&operator<<(char*str){for(int i=0;str[i];++i)putch(str[i]);return*this;}qostream&operator<<(const char*s){for(int i=0;s[i];++i)putch(s[i]);return*this;}}qcout(Fout); } #define cin IO::qcin #define cout IO::qcout const int mod=1000003579,base=13331,inf=0x7f7f7f7f; struct quality { int l,r,id; }; int hsh[500010],jc[500010],d[500010],st[500010],ed[500010],ans[500010]; char s[500010]; deque<char>t; vector<quality>ask[500010]; vector<pair<int,int> >change[500010]; void sx_hash(char s[],int len) { for(int i=0;i<=len;i++) { hsh[i]=(i==0)?0:(1ll*hsh[i-1]*base%mod+s[i])%mod; } } int ask_hash(int l,int r) { return (hsh[r]-1ll*hsh[l-1]*jc[r-l+1]%mod+mod)%mod; } int divide(int l,int r,int p) { int mid=0,ans=l; while(l<=r) { mid=(l+r)/2; if(ask_hash(st[mid],st[mid]+(mid-p)-1)==ask_hash(ed[mid]-(mid-p)+1,ed[mid])) { ans=mid; l=mid+1; } else { r=mid-1; } } return ans; } struct SMT { struct SegmentTree { int minn; }tree[2000010]; #define lson(rt) (rt<<1) #define rson(rt) (rt<<1|1) void pushup(int rt) { tree[rt].minn=min(tree[lson(rt)].minn,tree[rson(rt)].minn); } void build(int rt,int l,int r) { tree[rt].minn=inf; if(l==r) { return; } int mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); } void update(int rt,int l,int r,int pos,int val) { if(l==r) { tree[rt].minn=min(tree[rt].minn,val); return; } int mid=(l+r)/2; if(pos<=mid) { update(lson(rt),l,mid,pos,val); } else { update(rson(rt),mid+1,r,pos,val); } pushup(rt); } int query(int rt,int l,int r,int x,int y) { if(x<=l&&r<=y) { return tree[rt].minn; } int mid=(l+r)/2,ans=inf; if(x<=mid) { ans=min(ans,query(lson(rt),l,mid,x,y)); } if(y>mid) { ans=min(ans,query(rson(rt),mid+1,r,x,y)); } return ans; } }T; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif int n,m,q,l,r,k,i,j; cin>>n>>(s+1); jc[0]=1; for(i=1;i<=n;i++) { jc[i]=1ll*jc[i-1]*base%mod; if('a'<=s[i]&&s[i]<='z') { d[1]++; d[i]--; t.push_front(s[i]); } else { s[i]-='A'-'a'; t.push_back(s[i]); } } for(i=1;i<=n;i++) { s[i]=t.front(); t.pop_front(); } sx_hash(s,n); for(i=1;i<=n;i++) { d[i]+=d[i-1]; st[i]=1+d[i]; ed[i]=i+d[i]; } cin>>m; for(i=1;i<=m;i++) { cin>>k; change[divide(k,n,k)].push_back(make_pair(k,i)); } cin>>q; for(i=1;i<=q;i++) { cin>>k>>l>>r; ask[k].push_back((quality){l,r,i}); } T.build(1,1,m); for(i=n;i>=1;i--) { for(j=0;j<change[i].size();j++) { T.update(1,1,m,change[i][j].second,change[i][j].first); } for(j=0;j<ask[i].size();j++) { k=T.query(1,1,m,ask[i][j].l,ask[i][j].r); ans[ask[i][j].id]=((k<=i)?k:-1); } } for(i=1;i<=q;i++) { cout<<ans[i]<<endl; } return 0; }
QOJ 8701.Border
-
考虑枚举
,二分哈希求出 得到第一处不同的位置,这个位置必须被修改且修改后 。若找不到不同的位置且 说明 的答案至少为 ,打个标记即可。 -
特判
时答案为原串 长度。点击查看代码
const ll mod=1000003579,base=13331; ll a[2000010],jc[2000010],ans[2000010],lazy[2000010]; char s[2000010],t[2000010]; void sx_hash(char s[],ll len) { for(ll i=0;i<=len;i++) { a[i]=(i==0)?0:(a[i-1]*base%mod+s[i])%mod; } } ll ask_hash(ll l,ll r) { return (l<=r)?(a[r]-a[l-1]*jc[r-l+1]%mod+mod)%mod:0; } ll change_hash(ll l,ll r,ll pos) { return (l<=pos&&pos<=r)?(ask_hash(l,r)+(t[pos]-s[pos])*jc[r-pos]%mod+mod)%mod:ask_hash(l,r); } ll lcp(ll x,ll y,ll len) { ll l=1,r=len,mid,ans=0; while(l<=r) { mid=(l+r)/2; if(ask_hash(x,x+mid-1)==ask_hash(y,y+mid-1)) { ans=mid; l=mid+1; } else { r=mid-1; } } return ans; } int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll n,len,border=0,i; cin>>(s+1)>>(t+1); n=strlen(s+1); jc[0]=1; sx_hash(s,n); for(i=1;i<=n;i++) { jc[i]=jc[i-1]*base%mod; } for(i=1;i<=n-1;i++) { border=(ask_hash(1,i)==ask_hash(n-i+1,n))?i:border; len=lcp(1,n-i+1,i); if(len!=i) { if(s[len+1]!=t[len+1]&&change_hash(1,i,len+1)==change_hash(n-i+1,n,len+1)) { ans[len+1]=i; } if(s[n-i+1+len]!=t[n-i+1+len]&&change_hash(1,i,n-i+1+len)==change_hash(n-i+1,n,n-i+1+len)) { ans[n-i+1+len]=i; } } else { if(i<n-i+1) { lazy[i+1]=lazy[n-i]=i; } } } for(i=1;i<=n&&i<=n-i+1;i++) { lazy[i]=max(lazy[i],lazy[i-1]); } for(i=n;i>=1&&i>=n-i+1;i--) { lazy[i]=max(lazy[i],lazy[i+1]); } for(i=1;i<=n;i++) { cout<<((s[i]==t[i])?border:max(ans[i],lazy[i]))<<endl; } return 0; }
luogu P2375 [NOI2014] 动物园
QOJ 6842.Popcount Words
[AGC064C] Erase and Divide Game
LibreOJ 6070. 「2017 山东一轮集训 Day4」基因
CF906E Reverses
luogu P1117 [NOI2016] 优秀的拆分
-
AABB
串可以看做两个AA
串拼接起来,考虑求出以 结尾和开头的AA
串数量 。 -
枚举
A
长度 后再枚举左右端点使用后缀数组加速 计算的时间复杂度为 ,需要进一步优化。 -
仍枚举长度
,并将 的倍数的位置设置为关键点,则AA
串必然经过两个关键点。设当前枚举的相邻两个关键点分别为 ,考虑统计经过这两个关键点的数量。 -
恰好取到端点处的答案是容易处理的。端点在
左边和 右边时需要保证 。设 ,此时 均可以作为AA
串的结尾, 均可以作为AA
串的开头。- 建议画图理解。
-
差分完前缀和统计答案即可。
点击查看代码
ll f[30010],g[30010],n; char s[30010]; struct SA { struct ST { ll fminn[30010][20]; void init(ll n,ll a[]) { memset(fminn,0x3f,sizeof(fminn)); for(ll i=1;i<=n;i++) { fminn[i][0]=a[i]; } for(ll j=1;j<=log2(n);j++) { for(ll i=1;i+(1<<j)-1<=n;i++) { fminn[i][j]=min(fminn[i][j-1],fminn[i+(1<<(j-1))][j-1]); } } } ll query(ll l,ll r) { ll t=log2(r-l+1); return min(fminn[l][t],fminn[r-(1<<t)+1][t]); } }T; ll sa[30010],rk[60010],oldrk[60010],id[30010],cnt[30010],key[30010],height[30010]; ll val(char x) { return (ll)x; } void counting_sort(ll n,ll m) { memset(cnt,0,sizeof(cnt)); for(ll i=1;i<=n;i++) { cnt[key[i]]++; } for(ll i=1;i<=m;i++) { cnt[i]+=cnt[i-1]; } for(ll i=n;i>=1;i--) { sa[cnt[key[i]]]=id[i]; cnt[key[i]]--; } } void init(char s[],ll len) { ll m=127,tot=0,num=0; for(ll i=1;i<=len;i++) { rk[i]=val(s[i]); id[i]=i; key[i]=rk[id[i]]; } counting_sort(len,m); for(ll w=1;tot!=len;w<<=1,m=tot) { num=0; for(ll i=len;i>=len-w+1;i--) { num++; id[num]=i; } for(ll i=1;i<=len;i++) { if(sa[i]>w) { num++; id[num]=sa[i]-w; } } for(ll i=1;i<=len;i++) { key[i]=rk[id[i]]; } counting_sort(len,m); for(ll i=1;i<=len;i++) { oldrk[i]=rk[i]; } tot=0; for(ll i=1;i<=len;i++) { tot+=(oldrk[sa[i]]!=oldrk[sa[i-1]]||oldrk[sa[i]+w]!=oldrk[sa[i-1]+w]); rk[sa[i]]=tot; } } for(ll i=1,j=0;i<=len;i++) { j-=(j>=1); while(s[i+j]==s[sa[rk[i]-1]+j]) { j++; } height[rk[i]]=j; } T.init(len,height); } ll lcp(ll x,ll y) { if(rk[x]>rk[y]) { swap(x,y); } return (x==y)?n-x+1:T.query(rk[x]+1,rk[y]); } }F,B; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll t,ans,len,lcp,lcs,i,j,k; cin>>t; for(k=1;k<=t;k++) { ans=0; memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); cin>>(s+1); n=strlen(s+1); F.init(s,n); reverse(s+1,s+1+n); B.init(s,n); for(len=1;len<=n/2;len++) { for(i=len,j=i+len;j<=n;i+=len,j+=len) { lcp=min(len,F.lcp(i,j)); lcs=min(len-1,B.lcp(n-(i-1)+1,n-(j-1)+1)); if(lcp+lcs>=len) { f[j+lcp-(lcs+lcp-len)-1]++; f[j+lcp]--; g[(i-1)-lcs+1]++; g[(i-1)-lcs+(lcs+lcp-len)+2]--; } } } for(i=1;i<=n;i++) { f[i]+=f[i-1]; g[i]+=g[i-1]; } for(i=1;i<=n-1;i++) { ans+=f[i]*g[i+1]; } cout<<ans<<endl; } return 0; }
luogu P9482 [NOI2023] 字符串
luogu P9623 [ICPC2020 Nanjing R] Baby's First Suffix Array Problem
[ARC175F] Append Same Characters
luogu P4218 [CTSC2010] 珠宝商
CF1276F Asterisk Substrings
CF1817F Entangled Substrings
UOJ 577.【ULR #1】打击复读
UOJ 697.【候选队互测2022】广为人知题
QOJ 9639.字符串
CF1393E2 Twilight and Ancient Scroll (harder version)
luogu P4482 [BJWC2018] Border 的四种求法
luogu P8351 [SDOI/SXOI2022] 子串统计
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18639568,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】