zoukankan      html  css  js  c++  java
  • CF653F Paper task

    题面
    英文题面
    题意:给定一个长度为(n)的括号串,问有多少种不同的合法括号子串。
    (n leq 5 imes 10^5)
    题解:
    先考虑暴力的做法:枚举左端点,然后每次扫一遍,有括号平衡就将其加入答案,再用哈希+map判一下重。
    再考虑不需要去重时的快速做法。
    (s_i)表示前(i)个字符,左括号个数与右括号个数的差。发现当固定左端点(l)时,合法的右端点(r)需要满足:
    1.(s_l = s_r)
    2.(forall_{i=l}^{r} , s_i geq s_l)
    所以我们开一个树状数组记一下权值,枚举左端点,二分出满足第二个限制的最大的(r),在树状数组上查询即可。
    二分的check可以用rmq做到O(1)查询。
    那么如何去重呢?考虑后缀数组的height数组的意义,不难发现对于每个(l),答案只需要减去(r)([l,l+height_{rank_l}-1])这段的贡献即可。
    时间复杂度:(O(nlogn))
    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    char c[505000];
    int n,m,buc[505000],sa[505000],tot,rk[505000],tp[505000],hei[505000];
    int s[505000],f[505000][22],lg[505000];
    vector<int>st[1010000];
    ll ans;
    I build_sa(){
    	m=2;
    	F(i,1,n)buc[rk[i]=(c[i]=='('?1:2)]++;
    	F(i,1,m)buc[i]+=buc[i-1];
    	FOR(i,n,1)sa[buc[rk[i]]--]=i;
    	for(re k=1;k<=n;k<<=1){
    		tot=0;
    		F(i,n-k+1,n)tp[++tot]=i;
    		F(i,1,n)if(sa[i]>k)tp[++tot]=sa[i]-k;
    		F(i,1,m)buc[i]=0;
    		F(i,1,n)buc[rk[i]]++;
    		F(i,1,m)buc[i]+=buc[i-1];
    		FOR(i,n,1)sa[buc[rk[tp[i]]]--]=tp[i],tp[i]=0;
    		swap(rk,tp);
    		rk[sa[1]]=tot=1;
    		F(i,2,n)rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+k]==tp[sa[i]+k])?tot:++tot;
    		if(tot==n)break;
    		m=tot;
    	}
    	re k=0;
    	F(i,1,n){
    		if(rk[i]==1)continue;
    		if(k)k--;
    		re p=sa[rk[i]-1];
    		while(c[i+k]==c[p+k])k++;
    		hei[rk[i]]=k;
    	}
    //	F(i,1,n)cout<<sa[i]<<" ";cout<<endl;
    //	F(i,1,n)cout<<rk[i]<<" ";cout<<endl;
    //	F(i,1,n)cout<<hei[i]<<" ";cout<<endl;
    }
    I build_rmq(){
    	F(i,1,n)s[i]=s[i-1]+(c[i]=='('?1:-1);
    	F(i,0,n<<1)st[i].emplace_back(0);
    	F(i,1,n)s[i]+=n,st[s[i]].emplace_back(i);s[0]=n;
    	lg[0]=-1;F(i,1,n)lg[i]=lg[i>>1]+1,f[i][0]=s[i];
    	F(j,1,lg[n])F(i,1,n-(1<<j)+1)f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
    }
    IN ques_min(int l,int r){
    	re len=lg[r-l+1];
    	return min(f[l][len],f[r-(1<<len)+1][len]);
    }
    IN ques(int l,int r){
    	if(l>=r||c[l]==')')return 0;
    	re x=l,y=r,mid,w=s[l-1],res;
    	while(x!=y){
    		mid=(x+y+1)>>1;
    		if(ques_min(l,mid)>=w)x=mid;
    		else y=mid-1;
    //		cout<<x<<" "<<y<<endl;
    	}
    //	cout<<w<<":";
    //	for(auto d:st[w])cout<<d<<" ";cout<<endl;
    	res=(upper_bound(st[w].begin(),st[w].end(),x)-st[w].begin())-(upper_bound(st[w].begin(),st[w].end(),l-1)-st[w].begin());
    //	cout<<"!"<<l<<" "<<r<<" "<<x<<" "<<w<<" "<<upper_bound(st[w].begin(),st[w].end(),x)-st[w].begin()<<" "<<res<<endl;
    	return res;
    }
    int main(){
    	ios::sync_with_stdio(false);cin.tie(0);
    	cin>>n>>c+1;
    	build_sa();build_rmq();
    //	while(1){
    //		int l,r;cin>>l>>r;cout<<ques_min(l,r)<<endl;
    //	}
    	F(i,1,n)ans+=ques(sa[i],n)-ques(sa[i],sa[i]+hei[i]-1);
    	cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    信息的概念
    信息管理学基础
    第一章关键术语
    企业的转变
    国外的信息系统概念
    管理信息系统的基本功能
    人机交互设计-评价输入法-课下作业
    《构建之法》一
    27日进度
    26号进度
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/13263753.html
Copyright © 2011-2022 走看看