1 条题解
-
0
自动搬运
来自洛谷,原作者为

do_while_true
水搬运于
2025-08-24 22:45:25,当前版本为作者最后更新于2024-02-20 14:13:56,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文


像一棵海草海草海草海草,浪花里舞蹈。
差不多是抄来的题解/wq。
首先对 作猫树分治,把询问挂在第一次分割出它的那个节点处。现在需要做的问题就是需要快速处理这样的询问 ,询问 时利用其处理出 每个前缀和 左半区间后缀的 LCS,每个后缀和 右半区间前缀的 LCS,再选最优的拼接方案即可。不考虑处理 LCS,这部分的时间复杂度是 的。
考虑这样的性质:
①:$f(i-1,j,k)>f(i-1,j-1,k)\Rightarrow f(i,j,k)>f(i,j-1,k)$
②:$f(i,j,k)>f(i,j,k-1)\Rightarrow f(i-1,j,k)>f(i-1,j,k-1)$
这里照抄一下证明。考虑一张网格图,如果 则 有一条斜向上的路径,将 LCS 视作一条斜向上次数最多的路径。
对于 ①,考虑 到 的路径 ,与 到 的路径 ,它们代表了 。它们必有一交点,假设为 。将 在 之前的路径替换为 在 之前的路径,得到一条 的路径,根据假设有 后面的路径满足 。
同样地将 在 之后的路径替换为 在 之后的路径,得到一条路径 满足 的路径 ,而 替换了一个更大的路径得到 ,于是有 ,得证。
对于 ② 也是同理的。
这两条性质表明:
①: 时,会 的是个后缀,记为 ( 是 后的, 的 )。
②: 时,会 的是个前缀,记为 ( 是 后的, 的 )。
我们令 。
当 时,若 :

对比 和 得 ,对比 和 得 。
当 且 时:

对比 和 , 和 得到:.
类似地, 时, 一定为 ,此时 。综上,我们得到了:
$$(p(k,j),q(k,j))=\left\{\begin{matrix} (P,Q) & X_j\neq Y_k,P\geq Q\\ (Q,P) & otherwise \end{matrix}\right. $$初始 ,将 都递推出来后再处理原问题只需用差分得到 。
对于挂着询问的线段树节点都要 跑出来 ,所以总的时间复杂度是 。
#include<cstdio> #include<vector> #include<queue> #include<cstring> #include<iostream> #include<algorithm> #include<ctime> #include<random> #include<assert.h> #define pb emplace_back #define mp make_pair #define fi first #define se second #define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<<x<<'\n' #define dpi(x,y) cerr<<"In Line "<<__LINE__<<" the "<<#x<<" = "<<x<<" ; "<<"the "<<#y<<" = "<<y<<'\n' using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int>pii; typedef pair<ll,int>pli; typedef pair<ll,ll>pll; typedef pair<int,ll>pil; typedef vector<int>vi; typedef vector<ll>vll; typedef vector<pii>vpii; typedef vector<pll>vpll; template<typename T>T cmax(T &x, T y){return x=x>y?x:y;} template<typename T>T cmin(T &x, T y){return x=x<y?x:y;} template<typename T> T &read(T &r){ r=0;bool w=0;char ch=getchar(); while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar(); while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar(); return r=w?-r:r; } template<typename T1,typename... T2> void read(T1 &x,T2& ...y){read(x);read(y...);} const int N=3010; struct DS{ int n,m; char s[N],t[N]; int p[N][N],q[N][N],o[N][N]; //LCS(s[i,j], t[1,k]) void solve(){ for(int i=0;i<=n;i++)p[i][0]=i+1; for(int i=0;i<=m;i++)q[0][i]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ const int P=p[i][j-1],Q=q[i-1][j]; if(s[i]!=t[j]&&P>=Q)p[i][j]=P,q[i][j]=Q; else p[i][j]=Q,q[i][j]=P; } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) o[j][i]=p[i][j]; } }ds1,ds2; int n,m,q; char s[N],t[N]; struct Node{ int a,b,c,d,id; }; vector<Node>vec[N*4]; void modify(int x,int tl,int tr,Node &o){ int mid=(tl+tr)>>1; if(o.b<=mid)modify(x<<1,tl,mid,o); else if(o.a>mid)modify((x<<1)|1,mid+1,tr,o); else vec[x].push_back(o); } int s1[N],s2[N],ans[100010]; void dfs(int x,int tl,int tr){ if(tl==tr)return ; int mid=(tl+tr)>>1; if(!vec[x].empty()){ ds1.m=0; for(int i=mid;i>=tl;i--)ds1.t[++ds1.m]=s[i]; ds1.solve(); ds2.m=0; for(int i=mid+1;i<=tr;i++)ds2.t[++ds2.m]=s[i]; ds2.solve(); for(auto o:vec[x]){ int a=o.a,b=o.b,c=o.c,d=o.d,id=o.id; for(int i=c-1;i<=d+1;i++)s1[i]=s2[i]=0; for(int i=m-d+1;i<=m-c+1;i++){ int l=m-i+1,r=m-ds1.o[mid-a+1][i]+1; s1[l]++,s1[r+1]--; } for(int i=c;i<=d+1;i++)s1[i]+=s1[i-1]; for(int i=c;i<=d;i++){ int l=max(c,ds2.o[b-mid][i]),r=i; if(l<=r) s2[l]++,s2[r+1]--; } for(int i=c;i<=d+1;i++)s2[i]+=s2[i-1]; int mx=0; for(int i=c;i<=d+1;i++) mx=max(mx,s1[i-1]+s2[i]); ans[id]=mx; } } dfs(x<<1,tl,mid); dfs((x<<1)|1,mid+1,tr); } signed main(){ read(n);read(m);read(q); scanf("%s%s",s+1,t+1); ds1.n=0; for(int i=m;i>=1;i--)ds1.s[++ds1.n]=t[i]; ds2.n=0; for(int i=1;i<=m;i++)ds2.s[++ds2.n]=t[i]; for(int i=1;i<=q;i++){ int a,b,c,d;read(a);read(b);read(c);read(d); Node o={a,b,c,d,i}; if(a!=b)modify(1,1,n,o); else{ for(int j=c;j<=d;j++) if(t[j]==s[a]){ ans[i]=1; break; } } } dfs(1,1,n); for(int i=1;i<=q;i++)cout << ans[i] << '\n'; return 0; }
- 1
信息
- ID
- 8421
- 时间
- 8000ms
- 内存
- 512MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者