一些有意思的科技(其二)

给两个字符串 \(A,B\) ,其长度分别为 \(n,m\) (同阶), \(q\) 次询问 \(l_1,r_1,l_2,r_2\)\(A[l_1,r_1]\)\(B[l_2,r_2]\)\(\text{LCS}\)

有一个算法 \(\text{ALCS}\) 可以做到 \(O(n^2 \log n+qn)\) ,原论文在这里

考虑把最经典的 \(\text{DP}\) 看作走网格,差不多长这样,横竖边权都为 \(0\) ,斜边边权为 \(1\)

我们令 \((x,y)\) 表示从左往右的 \(x\) 列,从上往下第 \(y\) 行(从 \(0\) 开始),一共有 \(n+1\) 列, \(m+1\)

考虑询问怎么做,考虑二维的分治,每次劈开大的那一维,假设是将横着的分成两半(就是这个图从中竖劈),这个时候我们需要处理的是跨过这条线,假设其为第 \(x\) 列的询问,我们枚举从 \((l_1,l_2)\) 走到 \((r_1,r_2)\) 时第一次与这条线相交的位置 \(i\) ,我们想分别求出 \((x,i)\) 走到 \((l_1,l_2)\)\((r_1,r_2)\) 的最长路

这样我们的问题就转化为了快速的求出一些 \(C^{l}(x,r)\) 表示在一张网格图上从 \((0,l)\) 走到 \((x,r)\) 的最长路,注意到有性质

  1. 若对于 \(1 \le l<r \le m\) ,有 \(C^{l-1}(x,r-1)+1=C^{l-1}(x,r)\) ,则有 \(C^{l}(x,r-1)+1=C^{l}(x,r)\)

  2. 若对于 \(1 \le l<r \le m,x>0\) ,有 \(C^{l-1}(x-1,r)=C^{l-1}(x,r)\) ,则有 \(C^{l}(x-1,r)=C^{l}(x,r)\)

证明注意到最靠左的最优的路径后缀不变即可

所以若我们能求出 \(ih_{x,y}\) 表示所有 \(C^{i}(x,y)\) 满足性质 \(1\) 的最小的 \(i\)\(iv_{x,y}\) 表示满足性质 \(2\) 的最小的 \(i\) ,转移讨论一下 \(a_x\)\(b_y\) 是否相等即可,具体可以看代码

在求出 \(ih_{x,y}\) 以后,对于固定的 \((x,y)\) 可以通过区间加求出所有的 \(C^{i}(x,y)\) ,显然可以用差分做到 \(O(n)\) 求,这样就搞定了,可以看代码理解理解

点击查看代码
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>

#define maxn 2222
#define maxm 101101

template<class T>

inline T read(){
	T r=0,f=0;
	char c;
	while(!isdigit(c=getchar()))f|=(c=='-');
	while(isdigit(c))r=(r*10)+(c^48),c=getchar();
	return f?-r:r;
}

template<class T>

inline T min(T a,T b){
	return a<b?a:b;
}

template<class T>

inline T max(T a,T b){
	return a>b?a:b;
}

template<class T>

inline void chkmax(T &a,T b){
	a=a>b?a:b;
}

struct Q{
	int l1,r1,l2,r2;
}qry[maxm];

int n,m,q,ans[maxm];

#define vec std::vector<int>

struct ALCS{

	int iv[maxn][maxn],ih[maxn][maxn];

	inline void init(vec &a,vec &b){
		int n=a.size(),m=b.size();
		for(int i=0;i<=n;i++)iv[i][0]=0;
		for(int j=0;j<=m;j++)ih[0][j]=j;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++){
				if(a[i-1]^b[j-1]){
					ih[i][j]=max(iv[i][j-1],ih[i-1][j]);
					iv[i][j]=iv[i][j-1]^ih[i-1][j]^ih[i][j];
				}
				else ih[i][j]=iv[i][j-1],iv[i][j]=ih[i-1][j];
			}
	}

	inline void calcrow(int m,int i,int *sum){
		for(int j=0;j<=m;j++)sum[j]=0;
		for(int j=1;j<=m;j++)
			if(ih[i][j]<j)sum[ih[i][j]]++,sum[j]--;
		for(int j=1;j<m;j++)sum[j]+=sum[j-1];
	    sum[m]=0,std::reverse(sum,sum+m+1);
	}

}alcs[2];

int suml[maxn],sumr[maxn];

inline void calc(int mid,int m,vec &ask){
	for(auto p:ask){
		int l1=qry[p].l1,r1=qry[p].r1;
		int l2=qry[p].l2,r2=qry[p].r2;
		int len=r2-l2+1,len1=m-l2+1,len2=r2;
		alcs[0].calcrow(len1,mid-l1+1,suml);
		alcs[1].calcrow(len2,r1-mid,sumr);
		for(int k=max(len-len2,0),lim=min(len,len1);k<=lim;k++)
		    chkmax(ans[p],suml[k]+sumr[len-k]);
	}
}

inline void solve(vec &a,vec b,vec &ask){
	if(ask.empty())return;
	if(a.size()<b.size()){
		std::swap(a,b);
		for(auto p:ask){
			std::swap(qry[p].l1,qry[p].l2);
			std::swap(qry[p].r1,qry[p].r2);
		}
	}
	int mid=a.size()>>1;
	vec al=vec(a.begin(),a.begin()+mid);
	vec ar=vec(a.begin()+mid,a.end());
	std::reverse(al.begin(),al.end());
	std::reverse(b.begin(),b.end());
	alcs[0].init(al,b);
	std::reverse(al.begin(),al.end());
	std::reverse(b.begin(),b.end());
	alcs[1].init(ar,b);
	vec askl,askr,now;
	for(auto p:ask){
		if(qry[p].r1<mid)askl.push_back(p);
		else if(qry[p].l1>mid){
			qry[p].l1-=mid,qry[p].r1-=mid;
			askr.push_back(p);
		}
		else now.push_back(p);
	}
	calc(mid,b.size(),now);
	solve(al,b,askl),solve(ar,b,askr);
}

int cnta[maxn][maxn],cntb[maxn][maxn];

int main(){
	n=read<int>();
	m=read<int>();
	q=read<int>();
    vec a(n),b(m),ask;
	for(int i=0,V=0;i<n;i++){
		V=max(V,a[i]=read<int>());
		for(int j=0;j<=V;j++)
			cnta[i+1][j]=cnta[i][j]+(j==a[i]);
	}
	for(int i=0,V=0;i<m;i++){
		V=max(V,b[i]=read<int>());
		for(int j=0;j<=V;j++)
			cntb[i+1][j]=cntb[i][j]+(j==b[i]);
	}
	for(int i=1;i<=q;i++){
		qry[i].l1=read<int>();
		qry[i].r1=read<int>();
		qry[i].l2=read<int>();
		qry[i].r2=read<int>();
		if(qry[i].l1==qry[i].r1){
			int x=a[qry[i].l1-1];
			ans[i]=cntb[qry[i].r2][x]>cntb[qry[i].l2-1][x];
		}
		else if(qry[i].l2==qry[i].r2){
			int x=b[qry[i].l2-1];
			ans[i]=cnta[qry[i].r1][x]>cnta[qry[i].l1-1][x];
		}
		else ask.push_back(i);
	}
	solve(a,b,ask);
	for(int i=1;i<=q;i++)
		printf("%d\n",ans[i]);
	return 0;
}
posted @ 2023-03-17 20:07  一叶知秋‘  阅读(25)  评论(0编辑  收藏  举报