1 条题解

  • 0
    @ 2025-8-24 22:52:37

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar meyi
    明日黄花

    搬运于2025-08-24 22:52:37,当前版本为作者最后更新于2023-11-23 14:53:37,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    2023/11/30 upd: 感谢 zyc212303 指出一处 typo。

    貌似写了个常数比较小的做法,目前洛谷最优解 rk1 390ms,比 rk2 825ms 快了一倍。

    首先由 s2=s5,s3=s6s_2=s_5, s_3=s_6 可知 s2+s3=s5+s6s_2+s_3=s_5+s_6,不妨将它们合并起来看,那么题意就转化为了:定义字符串 tt 是美丽的当且仅当将可以 tt 视作 t1+t2+t3+t4t_1+t_2+t_3+t_4,满足 t1,t2,t3,t4t_1,t_2,t_3,t_4 均非空,且 t1t_1t2t_2 的真前缀,t2=t4t_2=t_4,给定字符串 ss,求其有多少子串是美丽的。

    考虑 O(n2)O(n^2)lcp\text{lcp} 的过程,若 iijjlcp\text{lcp}kk,那么可以将 t2t_2 视作 si..i+l1s_{i..i+l-1},将 t4t_4 视作 sj,j+l1s_{j,j+l-1}(1lk)(1\le l\le k),由于 t3t_3 的存在,因此还需要满足 l<jil< j-i。故我们可以预处理 sumi,lsum_{i,l} 表示以 ii 开头长度为 >l>l 的选择 t2t_2t4t_4 的方案数,那么每个 jjsumisum_i 的贡献是一个等差数列的形式,使用两个前缀和数组处理即可。最后注意到这里的 t2t_2 是唯一确定的,因此不会重复计数。

    然后考虑 t1t_1 怎么枚举,仍然是在求 lcp\text{lcp} 的过程中,设 iijjlcp\text{lcp}kk,若 i+kji+k\ge j,则说明 si,j1s_{i,j-1} 可以成为 t1t_1,答案只需累加 sumj,jisum_{j,j-i} 即可。

    时间复杂度 O(n2)O(n^2)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    //#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops")
    #define ALL(v) v.begin(),v.end()
    #define For(i,_) for(int i=0,i##end=_;i<i##end;++i) // [0,_)
    #define FOR(i,_,__) for(int i=_,i##end=__;i<i##end;++i) // [_,__)
    #define Rep(i,_) for(int i=(_)-1;i>=0;--i) // [0,_)
    #define REP(i,_,__) for(int i=(__)-1,i##end=_;i>=i##end;--i) // [_,__)
    typedef long long ll;
    typedef unsigned long long ull;
    #define V vector
    #define pb push_back
    #define pf push_front
    #define qb pop_back
    #define qf pop_front
    #define eb emplace_back
    typedef pair<int,int> pii;
    typedef pair<ll,int> pli;
    #define fi first
    #define se second
    const int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}},inf=0x3f3f3f3f,mod=1e9+7;
    const ll infl=0x3f3f3f3f3f3f3f3fll;
    template<class T>inline bool ckmin(T &x,const T &y){return x>y?x=y,1:0;}
    template<class T>inline bool ckmax(T &x,const T &y){return x<y?x=y,1:0;}
    int init=[](){return cin.tie(nullptr)->sync_with_stdio(false),0;}();
    int main(){
    	int t_case=1;
    	cin>>t_case;
    	while(t_case--){
    		string s;
    		cin>>s;
    		ll ans=0;
    		int n=s.size();
    		V<int>lcp(n);
    		V<V<int>>sum(n);
    		Rep(i,n){
    			sum[i].resize(n-i-1>>1);
    			V<int>sum2(sum.size());
    			FOR(j,i+1,n){
    				if(s[i]==s[j]){
    					lcp[j]=(j+1<n?lcp[j+1]:0)+1;
    					if(i+lcp[j]>=j&&j-i<sum[j].size())ans+=sum[j][j-i];
    					if(sum[i].size()){
    						int ed=min(j-i-1,lcp[j]);
    						sum[i][0]+=ed,--sum2[0];
    						if(ed<sum[i].size())++sum2[ed];
    					}
    				}
    				else lcp[j]=0;
    			}
    			FOR(j,1,sum[i].size())sum[i][j]+=sum[i][j-1]+sum2[j-1],sum2[j]+=sum2[j-1];
    		}
    		printf("%lld\n",ans);
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    9405
    时间
    3000ms
    内存
    1024MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者