2024.11.12 鲜花

P11270 【MX-S5-T4】魔法少女们 题解

这世界那么多人
这世界有那么多人
人群里 敞着一扇门
我迷朦的眼睛里长存
初见你蓝色清晨
这世界有那么多人
多幸运 我有个我们
这悠长命运中的晨昏
常让我 望远方出神
灰树叶飘转在池塘
看飞机轰的一声去远乡
光阴的长廊 脚步声叫嚷
灯一亮 无人的空荡
晚风中闪过 几帧从前啊
飞驰中旋转 已不见了吗
远光中走来 你一身晴朗
身旁那么多人 可世界不声 不响
这世界有那么多人
多幸运 我有个我们
这悠长命运中的晨昏
常让我 望远方出神
灰树叶飘转在池塘
看飞机轰的一声去远乡
光阴的长廊 脚步声叫嚷
灯一亮 无人的空荡
晚风中闪过 几帧从前啊
飞驰中旋转 已不见了吗
远光中走来 你一身晴朗
身旁那么多人 可世界不声 不响
笑声中浮过 几张旧模样
留在梦田里 永远不散场
暖光中醒来 好多话要讲
世界那么多人 可是它不声 不响
这世界有那么个人
活在我 飞扬的青春
在泪水里浸湿过的长吻
常让我 想啊想出神

最近都在写多项式卷积,换换脑子,写点一点也不清新的逆天题。

首先先去除不合法的 \(S,T\),具体的就是不能通过在后面/前面加右/左括号变成合法括号序的。

考虑经典做法,设 (\(-1\))\(1\),设一个括号序 \(X\) 的值 \(V(X)\) 为其所有括号的值和。

首先我会暴力,考虑枚举 \(S,T\) 分别做前后缀,统计个数。分讨:\(|S|+|T|\le k\)\(|S|+|K|>k\)\(|S|+|K|>k\) 能成立当且仅当它们相交的部分相同,且拼成的括号序合法,因为前后缀分别合法,所以括号序合法等价于拼成的值为 \(0\),维护 \(S,T\) 的 hash 和 \(V\) 的前缀轻松判。

\(|S|+|T|\le k\) 略微困难,考虑中间空余填法方案,其相当于是从 \(a \to b\),每次 \(\pm 1\),在任意时刻前缀和 \(\le 0\),这是经典格路计数,可以直接上卡特兰数/反射容斥,单次查询可以做到 \(O(1)\)

现在复杂度是 \(n^2\) 的,实现精细可以过 \(56pts\),考虑优化。

\(|S|+|K|>k\) 依然比较简单,考虑将后缀 hash,长度和 \(V\) 做成三元组扔进 hash 表,前缀直接查。

\(|S|+|T|\le k\) 考虑一个括号序的长度和值完全一样显然是没有区别的,将它们扔进一个等价类一起算,题解说是 \(L^{\frac{2}{3}}\) 种等价类,不会正,但因为总长和单个长度的限制确实不会太多,于是有了 \(84pts\)

考虑继续优化 \(|S|+|T|\le k\),发现对于 \((l,s)\) 的二元等价类,\(l\) 是长度,\(s\) 是值,显然可以拆成 \((l+1,s+1),(l+1,s-1)\),即考虑填上一个括号,于是根号分治,直接将 \(l<\sqrt L\) 的都推到 \(\sqrt L\),显然复杂度是 \(\mathcal{O}((\sqrt L)^2+(\sqrt L+\frac{L}{\sqrt L})^2)=\mathcal{O}(L)\)

一些细节:\(|S|+|K|>k\) 需要卡场,可以枚举断点,这样可以往 hash 表少扔几个元素,实在不行手写,\(|S|+|T|\le k\) 部分推到根号是要考虑有的前缀和后缀的匹配会被推成相交,在恰好接上时计算贡献即可。阈值分治的阈值开小点跑的比较快,算 hash 和 \(V\) 的时候不建议用 vector,反正我的暴力改成拼多多(开一个大数组动态分配空间)直接 \(44pts\to 56pts\)

Code
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;
using llt=long long;
using llf=long double;
using ull=unsigned long long;
#define endl '\n'
#define Il __always_inline
#ifdef LOCAL
	FILE *InFile=freopen("in_out/in.in","r",stdin),*OutFile=freopen("in_out/out.out","w",stdout);
#else
    FILE *InFile=stdin,*OutFile=stdout;
#endif

const int N=2e5+3,M=5e5+3,S=1e7+3,HBs=2333,MOD=1e9+7;
int Add(int a,int b){return (a+=b)>=MOD?a-MOD:a;}
int Sub(int a,int b){return (a-=b)<0?a+MOD:a;}

int n,m,ck,ans,fac[M],ivf[M],mln; ull hpw[M];

namespace Node{
	ull chs[S+N<<1],*hp=chs; int csm[S+N<<1],*sp=csm;
	struct Nd{
		ull *hs; int *sm; int len,sum;
		Il void In(const string &s){
			len=s.size(); hs=hp,hp+=len+2,sm=sp,sp+=len+2; mln=max(mln,len);
			hs[0]=0,sm[0]=0,sum=0; int p=0; ull hsh=0;
			for(auto c:s) ++p,hs[p]=hsh=hsh*HBs+c,sm[p]=sum+=c=='('?1:-1;
		}
		Il int Sm()const{return sum;}
		Il ull Hs(int l,int r){return hs[r]-hs[l-1]*hpw[r-l+1];}
	};
}using Node::Nd;
Nd s[N],t[N]; int lns,lnt;

Il int C(int a,int b){return a<b||b<0?0:1ll*fac[a]*ivf[b]%MOD*ivf[a-b]%MOD;}
Il int P(int a,int b,int c,int d){return C(c-a+d-b,d-b);}
Il int Cat(int a,int b,int c,int d){return Sub(P(a,b,c,d),P(a,b,d-1,c+1));}
Il int Cnt(int x,int y,int l){int a=(y-x+l)>>1,b=(x-y+l)>>1; return a+b==l?Cat(x,0,x+a,b):0;}

Il bool Chkl(const string &a){
	int sum=0;
	for(auto c:a) if((sum+=c=='('?1:-1)<0) return 0;
	return 1;
}
Il bool Chkr(const string &a){
	int sum=0;
	for(auto c=a.rbegin();c!=a.rend();++c) if((sum+=*c==')'?1:-1)<0) return 0;
	return 1;
}

Il size_t Hash(const tuple<ull,int,int> &p){return get<0>(p)+hash<int>()(get<1>(p))*HBs^hash<int>()(get<2>(p));};
struct Map{
	static const int MMOD=10000019;
	struct O{tuple<ull,int,int> v; int w,t;}o[200050];
	int n,c,w,h[MMOD],p[200050];
	void Clr(){for(int i=1;i<=w;++i) h[p[i]]=0; c=w=0;}
	void Ins(const tuple<ull,int,int> &x){
		int u=Hash(x)%MMOD;
		for(int i=h[u];i;i=o[i].t) if(o[i].v==x) return ++o[i].w,void();
		o[++c]={x,1,h[u]},h[u]=c,p[++w]=u;
	}
	int Get(const tuple<ull,int,int> &x){
		int u=Hash(x)%MMOD;
		for(int i=h[u];i;i=o[i].t) if(o[i].v==x) return o[i].w;
		return 0;
	}
} mp;
Il void Slv1(){
	sort(s+1,s+lns+1,[](const Nd &a,const Nd &b){return a.len==b.len?a.Sm()<b.Sm():a.len>b.len;});
	sort(t+1,t+lnt+1,[](const Nd &a,const Nd &b){return a.len==b.len?a.Sm()<b.Sm():a.len>b.len;});
	for(int i=1;i<=ck;++i){
		mp.Clr();
		for(int j=1;j<=lnt;++j){
			if(t[j].len<i) break;
			mp.Ins({t[j].hs[i],-t[j].Sm(),ck-t[j].len});
		}
		for(int j=1;j<=lns;++j){
			if(s[j].len<i) break;
			int l=s[j].len,p=l-i;
			ans=Add(ans,mp.Get({s[j].Hs(p+1,l),s[j].sm[p],p}));
		}
	}
}

Il void Slv2(){
	map<pair<int,int>,int> cs,ct; int B=min({ck/2-1,600,mln});
	map<pair<int,int>,int> cv;
	for(int i=1;i<=lns;++i) ++cs[{s[i].len,s[i].Sm()}];
	for(int i=1;i<=lnt;++i) ++ct[{t[i].len,t[i].Sm()}];
	for(auto k=cs.begin();k!=cs.end();){
		int l=k->first.first,s=k->first.second,t=k->second;
		if(l>=B) break; if(ct.count({ck-l,-s})) ans=(ans+1ll*ct[{ck-l,-s}]*t%MOD)%MOD;
		(cs[{l+1,s+1}]+=t)%=MOD; if(s>0) (cs[{l+1,s-1}]+=t)%=MOD; k=cs.erase(k);
	}
	for(auto k=ct.begin();k!=ct.end();){
		int l=k->first.first,s=k->first.second,t=k->second;
		if(l>=B) break; if(cs.count({ck-l,-s})) ans=(ans+1ll*cs[{ck-l,-s}]*t%MOD)%MOD;
		if(s<0) (ct[{l+1,s+1}]+=t)%=MOD; (ct[{l+1,s-1}]+=t)%=MOD; k=ct.erase(k);
	}
	for(auto l:cs) for(auto r:ct){
		int ll=l.first.first,rl=r.first.first,ls=l.first.second,rs=r.first.second,lt=l.second,rt=r.second;
		if(ll+rl<=ck) ans=(ans+1ll*Cnt(ls,-rs,ck-ll-rl)*lt%MOD*rt)%MOD;
	}
}

int main(){
	ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
	hpw[0]=1; for(int i=1;i<=M-3;++i) hpw[i]=hpw[i-1]*HBs;
	fac[0]=1; for(int i=1;i<=M-3;++i) fac[i]=1ll*fac[i-1]*i%MOD;
	ivf[M-3]=329292354; for(int i=M-3;i;--i) ivf[i-1]=1ll*ivf[i]*i%MOD;
	int cccc; cin>>cccc>>n>>m>>ck;
	for(int i=1;i<=n;++i){string a; cin>>a; if(Chkl(a)) s[++lns].In(a);}
	for(int i=1;i<=m;++i){string a; cin>>a; if(Chkr(a)) t[++lnt].In(a);}
	Slv1(); Slv2(); cout<<ans<<endl;
}
P


posted @ 2024-11-12 20:44  xrlong  阅读(63)  评论(4编辑  收藏  举报