首页 > 其他分享 >P5479 [BJOI2015] 隐身术 题解

P5479 [BJOI2015] 隐身术 题解

时间:2024-11-08 10:41:59浏览次数:1  
标签:int 题解 BJOI2015 fminn lens num 100010 隐身术 rk

题目传送门

前置知识

后缀数组简介 | 字符串哈希 | 二分

解法

考虑分别计算出编辑距离恰好等于 \(k_{0} \in [0,k]\) 的答案。

观察在编辑距离的存在下,长度差至多为 \(k\)。

考虑设 \(f_{i,j}\) 表示最大的 \(x\) 使得 \(s_{1 \sim x}\) 和 \(t_{1 \sim x+j}\) 可以在 \(i\) 次编辑内得到,即从 \(1\) 开始操作 \(i\) 次且长度增加 \(j\) 的最大匹配位置。

  • 显然 \(x,i\) 具有单调性。

转移时考虑截取一段 \(t\) 的后缀进行转移。

假设已经操作完了,那么 \(f_{i,j}\) 能向外延伸的就是 \(s_{f_{i,j}+1,|s|}\) 和 \(t_{f_{i,j}+j+1,|t|}\) 的公共前缀,查询 \(\operatorname{LCP}\) 进行更新即可。

\(\operatorname{LCP}\) 可以用二分哈希单次 \(O(\log n)\) 查询,也可以后缀数组 \(O(n \log n)\) 预处理完 \(O(1)\) 查询。
转移时考虑刷表,分别对 \(f_{i+1,j-1},f_{i+1,j},f_{i+1,j+1}\) 进行转移(三者分别对应删除、替换、添加)。

  • 注意下标为负数时的移位。

统计贡献时在遇到第一个合法的 \(i\) 加入贡献即可。

如果用后缀数组的话时间复杂度为 \(O(nk^{2}+n \log n)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
int f[15][25],ans[15];
char s[100010],t[100010],tmp[100010];
struct SA
{
	struct ST
	{
		int fminn[100010][25];
		void init(int n,int a[])
		{
			memset(fminn,0x3f,sizeof(fminn));
			for(int i=1;i<=n;i++)
			{
				fminn[i][0]=a[i]; 
			}
			for(int j=1;j<=log2(n);j++)
			{
				for(int i=1;i+(1<<j)-1<=n;i++)
				{
					fminn[i][j]=min(fminn[i][j-1],fminn[i+(1<<(j-1))][j-1]);
				}
			}
		}
		int query(int l,int r)
		{
			if(l>r)
			{
				swap(l,r);
			}
			l++;
			int t=log2(r-l+1);
			return min(fminn[l][t],fminn[r-(1<<t)+1][t]);
		}
	}T;
	int sa[100010],rk[200010],oldrk[200010],id[100010],cnt[100010],key[100010],height[100010];
	int val(char x)
	{
		return (int)x;
	}
	void counting_sort(int n,int m)
	{
		memset(cnt,0,sizeof(cnt));
		for(int i=1;i<=n;i++)
		{
			cnt[key[i]]++;
		}
		for(int i=1;i<=m;i++)
		{
			cnt[i]+=cnt[i-1];
		}
		for(int i=n;i>=1;i--)
		{
			sa[cnt[key[i]]]=id[i];
			cnt[key[i]]--;
		}
	}
	void init(char s[],int len)
	{
		int m=127,tot=0,num=0;
		for(int i=1;i<=len;i++)
		{
			rk[i]=val(s[i]);
			id[i]=i;
			key[i]=rk[id[i]];
		}
		counting_sort(len,m);
		for(int w=1;tot!=len;w<<=1,m=tot)
		{
			num=0;
			for(int i=len;i>=len-w+1;i--)
			{
				num++;
				id[num]=i;
			}
			for(int i=1;i<=len;i++)
			{
				if(sa[i]>w)
				{
					num++;
					id[num]=sa[i]-w;
				}
			}
			for(int i=1;i<=len;i++)
			{
				key[i]=rk[id[i]];
			}
			counting_sort(len,m);
			for(int i=1;i<=len;i++)
			{
				oldrk[i]=rk[i];
			}
			tot=0;
			for(int i=1;i<=len;i++)
			{
				tot+=(oldrk[sa[i]]!=oldrk[sa[i-1]]||oldrk[sa[i]+w]!=oldrk[sa[i-1]+w]);
				rk[sa[i]]=tot;
			}
		}
		for(int i=1,j=0;i<=len;i++)
		{
			j-=(j>=1);
			while(s[i+j]==s[sa[rk[i]-1]+j])
			{
				j++;
			}
			height[rk[i]]=j;
		}
		T.init(len,height);
	}
	int lcp(int x,int y)
	{
		return T.query(rk[x],rk[y]);
	}
}S;
int main()
{
	int k,lens,lent,sum=0,i,j,h;
	cin>>k>>(s+1)>>(t+1);
	lens=strlen(s+1);
	lent=strlen(t+1);
	for(i=1;i<=lens;i++)
	{
		tmp[i]=s[i];
	}
	tmp[lens+1]='&';
	for(i=1;i<=lent;i++)
	{
		tmp[lens+1+i]=t[i];
	}
	S.init(tmp,lens+1+lent);
	for(h=1;h<=lent;h++)
	{	
		memset(f,-0x3f,sizeof(f));
		f[0][k]=0;
		for(i=0;i<=k;i++)
		{
			for(j=-k;j<=k;j++)
			{
				if(f[i][j+k]>=0&&f[i][j+k]+j>=0&&f[i][j+k]+j+h-1<=lent)
				{
					if(f[i][j+k]+1<=lens&&f[i][j+k]+j+1+h-1+lens+1<=lens+1+lent)
					{
						f[i][j+k]+=S.lcp(f[i][j+k]+1,f[i][j+k]+j+1+h-1+lens+1);
					}
					if(j-1+k>=0)
					{
						f[i+1][j-1+k]=max(f[i+1][j-1+k],f[i][j+k]+(f[i][j+k]!=lens));
					}
					f[i+1][j+k]=max(f[i+1][j+k],f[i][j+k]+(f[i][j+k]!=lens));
					f[i+1][j+1+k]=max(f[i+1][j+1+k],f[i][j+k]);
				}
			}
		}
		for(j=-k;j<=k;j++)
		{
			for(i=0;i<=k;i++)
			{
				if(f[i][j+k]==lens&&lens+j>0&&lens+j+h-1<=lent)
				{
					ans[i]++;
					break;
				}
			}
		}
	}
	for(i=0;i<=k;i++)
	{
		sum+=ans[i];
	}
	cout<<sum<<endl;
	return 0;
}

后记

多倍经验:QOJ 5312.Levenshtein Distance

标签:int,题解,BJOI2015,fminn,lens,num,100010,隐身术,rk
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18534640

相关文章

  • P7984 [USACO21DEC] Tickets P 题解
    题目传送门前置知识线段树优化建图|最短路解法考虑对票建虚点,从\(c_{i}\)向\(i+n\)连一条权值为\(p_{i}\)的边,然后从\(i+n\)向\([a_{i},b_{i}]\)连一条权值为\(0\)的边。建出反图后\(1\toi\)和\(n\toi\)的路径集合会有重复统计的部分,不妨以\(dis_{1,i......
  • #473. 编辑 & P5479 [BJOI2015] 隐身术
    模拟赛出到加强版了,一点不会所以记录下。枚举每个后缀。设\(f_{i,j}\)为操作\(i\)次,长度增加\(j\),即插入的次数减删除的次数,所能匹配到的最大位置。也就是\(A\)的前\(f_{i,j}\)位匹配\(B\)的前\(f_{i,j}+j\)位。考虑转移。假如已经操作完了,那显然有\(f_{i,j}\ge......
  • 快速上手Docker部署Flask项目 附常见问题解决
    一、准备Flask项目1.项目结构有一个app.py文件作为主应用程序入口,内容示例:fromflaskimportFlaskapp=Flask(__name__)@app.route('/')defhello_world():return'Hello,World!'if__name__=='__main__':app.run(host='0.0.0.0&#......
  • P9192 [USACO23OPEN] Pareidolia P 题解
    P9192[USACO23OPEN]PareidoliaP题解首先自然考虑不带修的情况。考虑问题的本质就是求序列中尽量短的bessie序列个数。对于尽量短的理解是对于bessiebessie序列,不考虑其由\(1,8\sim12\)构成的序列,只考虑\(1\sim6,7\sim12\)组成的序列。于是考虑dp:设\(dp_{i......
  • CF1956F Nene and the Passing Game 题解
    处理很妙的题,部分细节请教了未来姚班zyl和LYH_cpp,在此鸣谢。首先考虑把题目给的式子进行转化,设\(i<j\),那么\(i\)和\(j\)能传球当且仅当\(l_i+l_j\lej-i\ler_i+r_j\)。移项并拆开得到,\(i+l_i\lej-l_i\)且\(i+r_i\gej-r_j\),如果画到数轴上的话......
  • 题解:P11253 [GDKOI2023 普及组] 小学生数学题
    所求的式子带除法,模意义下除法计算复杂度带\(\log\)太慢了,先改写成乘法:\(\sum_{i=1}^ni!\timesi^{-k}\)。想求这个式子,最简单的思路就是对于每个整数\(i\in[1,n]\),分别预处理出\(i!\)和\(i^{-k}\)的值,最后乘起来再\(O(n)\)暴力加起来就好了!对于\(i!\),注意到:\[i!=\b......
  • P4621 [COCI2012-2013#6] BAKTERIJE 题解
    一道很好的数学题。首先不难想到每个细菌的移动路线是有循环节的,循环节外的时间最多就是每个格子的四个方向都走一遍,也就是\(4\timesN\timesM\)。可以预处理每个细菌分别通过四个方向第一次到达终点的时间\(b_{i,0/1/2/3}\)和再次回到当前状态的循环节长度\(md_{i,0/1/2/......
  • 题解:[BZOJ2958] 序列染色
    ProblemLinkBZOJ2958序列染色题意给出一个长度为\(n\),由\(\ttB,W,X\)三种字符组成的字符串\(S\),你需要把每一个\(\ttX\)染成\(\ttB\)或\(\ttW\)中的一个。Solution字符串,染色,方案数,一眼\(dp\)。要求前半段是B,后半段是W。考虑容斥。\(f_{i,0/1},g_{i,......
  • IOR的脚本化、版本兼容性及常见问题解答
    脚本化IOR可以使用-f选项在命令行中使用输入脚本。在-f选项之前设置的命令行选项将被视为运行脚本的默认设置。例如:mpirun./ior-W-fscript将使用隐式-W运行脚本中的所有测试。脚本本身可以覆盖这些设置,并且可以设置为在一次执行下运行许多不同的IOR测试,重要的是要注意在-......
  • 【题解】CF1944
    CF1944A简要题意给定完全图删k条边使得从一号点开始的可达点最少Solution注意到最多需要删n-1条边就可以使得任意一个其他点都到达不了又注意到只要删的边少于n-1就可以从一号点走出去,主要走出去就可以走到任何点所以这题答案只有两种如果k≤n-1答案为n否则答案为1......