2024.8.8模拟赛16

模拟赛

重拾题解(刚刚写过一版忘保存了)

T1

其实就是个最长公共子序列的变形。把一样的数才匹配换成有倍数关系就匹配。

最长公共子序列:一般转化为最长上升子序列,即在一个串中的数 \(a\),找到它在另一个串中的位置 \(j\),从 \(1 \dots j-1\) 转移即可,取最大值可用树状数组维护前缀最大值。

本题需要找到在第一个串中每个数的倍数在第二个串中的位置,由于调和级数,只会有 \(log\) 个,然后转移时从后往前遍历,防止本层干扰。

code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int n,a[N],b[N],pos[N],f[N],c[N],ans;
vector<int> v[N];
inline bool cmp(int &x,int &y) {return x>y;}
inline void add(int x,int v)
{
	for(;x<=n;x+=(x&-x)) c[x]=max(c[x],v);
}
inline int que(int x)
{
	int res=0;
	for(;x;x-=(x&-x)) res=max(c[x],res);
	return res;
}
int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]),pos[b[i]]=i;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j*a[i]<=n;j++)
			v[i].push_back(pos[j*a[i]]);
		sort(v[i].begin(),v[i].end(),cmp);
		for(int j:v[i])
		{
			f[j]=max(f[j],que(j-1)+1);
			ans=max(ans,f[j]);
			add(j,f[j]);
		}
	}
	printf("%d\n",ans);
	return 0;
}

T2 大爷的字符串题

转化题意,就是查询区间众数

然后开始莫队 \(\mathbb{MQ}\)

一种直接用回滚,另一种可以维护每一个数在区间中的出现次数,然后再维护出现次数的出现次数

注意离散化。

其实挺板的。

code
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<unordered_map>
using namespace std;
#define mx(x,y) (x>y?x:y)
#define LL long long
const int N = 2e5+5;
int n,m,a[N],bl[N],tot;
struct Q {int l,r,id;} q[N];
int cnt[N],Cnt[N],ans[N],now;
unordered_map<int,int> mp;
inline bool cmp(Q &x,Q &y)
{
	return bl[x.l]==bl[y.l]?((bl[x.l]&1)?(x.r<y.r):(x.r>y.r)):bl[x.l]<bl[y.l];
}
inline void add(int x)
{
	Cnt[cnt[x]]--;
	cnt[x]++;
	Cnt[cnt[x]]++;
	now=mx(now,cnt[x]);
}
inline void del(int x)
{
	Cnt[cnt[x]]--;
	if(now==cnt[x]&&Cnt[cnt[x]]==0) now--;
	cnt[x]--;
	Cnt[cnt[x]]++;
}
void mq()
{
	for(int i=1,l=1,r=0;i<=m;i++)
	{
		int tl=q[i].l,tr=q[i].r;
		while(l<tl) del(a[l++]);
		while(l>tl) add(a[--l]);
		while(r>tr) del(a[r--]);
		while(r<tr) add(a[++r]);
		ans[q[i].id]=-now;
	}
}
int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	scanf("%d%d",&n,&m); int len=n/sqrt(m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]),bl[i]=(i-1)/len+1;
		if(!mp[a[i]]) mp[a[i]]=++tot;
		a[i]=mp[a[i]];
	}
	for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
	sort(q+1,q+1+m,cmp);
	mq();
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	return 0;
}

T3 Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

启发式合并。

注意理解题意,是每棵子树内最长的合法链

因为只有 \(22\) 位,所以考虑状压,一个串是否是回文串,我们只在乎其中出现次数为奇数的字符个数,所以用 \(1\) 表示出现奇数次,\(0\) 表示出现偶数次。

至于串的长度可以直接用深度差分得到。

依旧运用差分的思想,我们预处理根到每个点路径异或和,然后就可以从中截取一段路径。(以下状态都表示到根的异或和)

其实我们最终就是要找到某两个点之间的路径异或和为 \(0\) 或者只有一个 \(1\),那么对于某个状态 \(d[u]\),我们想找到的就是某个点的状态为 \(d[u]\)\(d[u]^(1<<i)\),这样两点间的路径就是合法的。

现在我们有了判断合法的方法,考虑如何对每一棵子树进行求解。如果直接遍历一定是 \(n^2\) 的,所以我们考虑用轻重链划分的方法进行启发式合并

我们选择整体维护重链的信息(全维护开不下),然后暴力遍历轻链,由于每次合并都会使需要遍历的轻链大小至少翻倍,所以复杂度 \(O(n\log n)\)

然后每次遍历一棵轻链,在已经合并的子树里找有没有能匹配合法的。然后注意我们维护的只是重儿子所在子树,所以对于那些轻儿子的信息要在处理完清空。

code
#include<bits/stdc++.h>
using namespace std;
#define mx(x,y) (x>y?x:y)
const int N = 1e6+5;
int n,ans[N];
int head[N],tot;
struct E {int u,v,w;} e[N<<1];
inline void add(int u,int v,int w) {e[++tot]={head[u],v,w}; head[u]=tot;}
int sz[N],son[N],dep[N],dfn[N],cnt,L[N],R[N],book[N*10],d[N];

inline void dfs(int u,int f)
{
	sz[u]=1; dep[u]=dep[f]+1; L[u]=++cnt; dfn[cnt]=u;
	for(int i=head[u];i;i=e[i].u)
	{
		int v=e[i].v; d[v]=d[u]^e[i].w;
		dfs(v,u); sz[u]+=sz[v]; 
		if(sz[son[u]]<sz[v]) son[u]=v;
	}
	R[u]=cnt;
}
inline void dfs2(int u,bool keep)
{
	for(int i=head[u];i;i=e[i].u)
	{
		int v=e[i].v; if(v==son[u]) continue;
		dfs2(v,0); ans[u]=mx(ans[u],ans[v]);
	}
	if(son[u]) dfs2(son[u],1),ans[u]=mx(ans[u],ans[son[u]]);
	if(book[d[u]]) ans[u]=mx(ans[u],book[d[u]]-dep[u]);
	for(int i=0;i<22;i++) if(book[d[u]^(1<<i)]) ans[u]=mx(ans[u],book[d[u]^(1<<i)]-dep[u]);
	book[d[u]]=mx(book[d[u]],dep[u]);
	for(int i=head[u];i;i=e[i].u)
	{
		int v=e[i].v; if(v==son[u]) continue;
		for(int j=L[v];j<=R[v];j++)
		{
			int x=dfn[j];
			if(book[d[x]]) ans[u]=mx(ans[u],book[d[x]]+dep[x]-(dep[u]<<1));
			for(int k=0;k<22;k++) if(book[d[x]^(1<<k)]) ans[u]=mx(ans[u],book[d[x]^(1<<k)]+dep[x]-(dep[u]<<1));
		}
		for(int j=L[v];j<=R[v];j++)
		{
			int x=dfn[j];
			book[d[x]]=mx(book[d[x]],dep[x]);
		}
	}
	if(!keep) for(int i=L[u];i<=R[u];i++) book[d[dfn[i]]]=0;
}

int main()
{
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	scanf("%d",&n);
	for(int i=2;i<=n;i++)
	{
		int x; char c; scanf("%d %c",&x,&c);
		add(x,i,1<<(c-'a'));
	}
	dfs(1,1); dfs2(1,1);
	for(int i=1;i<=n;i++) printf("%d ",ans[i]);
	return 0;
}
posted @ 2024-09-05 10:46  ppllxx_9G  阅读(17)  评论(1编辑  收藏  举报