2024.11.26模拟赛

昨天也打了模拟赛。但没补没总结。为什么呢。因为懒。

今天来了之后先犯困了一个坤小时。犯困的那两个半小时属于是连暴力都没法想怎么去写的那种。好不容易慢慢清醒了,又不想写了。随便打了个T3的暴力,又写了个T1的爆搜,结果爆搜炸了。

所以,今天昨天打的都很不怎么样。

结果考完之后,同学都说T3是去年提高组T3,我当时就是一个问号。

昨日作业链接

今日作业链接


Ehhh Ah


T1【成绩】

期望 不会


T2【插旗】

题目大意:

解题思路:

考虑深搜过程。对于一个节点的子树,它的最长链的长度一定会产生贡献(因为搜到最深后还到下一条链,这个长度很重要)。而搜到最后一条链时,它需要从最底端再回溯到子树之外,所以这条链的长度也会产生贡献。贪心地想,为了使得\(k\)最小,我们让最短链最后搜到。也就是说,对于一棵子树,它的最长链与最短链的长度会分别产生贡献。

具体咋写?细节有什么?我不道啊,我没写


T3【括号序列加强版】

题目大意:

解题思路:

暴力\(dp\)的复杂度是\(O(n^{3})\),而且分拿的很少 这对于我这个蒟蒻来讲非常不友好www 。于是考虑设一维状态\(f_{i}\)表示以\(s_{i}\)结尾的合法子串个数 可恶我本来也向这个方向想了但没想出来

对于\(f_{i}\),一定存在 \(j<i\) 使得 \(f_{i}\)\(f_{j}\) 转移而来,使得 \([\ j+1,i\ ]\) 合法;而为了答案不重不漏,那么它一定是由最大的满足条件的 \(j\) 转移而来,也就是说\(f_{i}\) 一定是从以\(i\)结尾、长度最短的合法区间\([\ j+1,i\ ]\)转移而来。用 \(lst_{i}\) 记录 \(j+1\),有状态转移方程:

\[f_{i}=f_{lat_{i}-1}+1 \]

现在考虑怎么求\(lst_{i}\)

因为\([\ lst_{i},i\ ]\)一定是最短的合法区间,那么它一定满足\(a_{lst_{i}}=a_{i}\)且区间\([\ lst_{i}+1,i-1\ ]\)合法。循环去求就行,若不存在,那么\(lst_{i}\)就为0。

代码如下↓

int j=i-1;
while (j>0&&a[i]!=a[j]) j=lst[j]-1;
lst[i]=j;

长得很像KMP求\(nxt\)数组的代码。

所以我们坚信它的时间复杂度和KMP的一样,均摊下来是\(O(n)\)

代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5;
int n;
int a[N];
int lst[N];
int f[N];
int ans;

signed main()
{
	scanf("%lld",&n);
	for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
	
	for (int i=1;i<=n;i++)
	{
		int j=i-1;
		while (j>0&&a[i]!=a[j]) j=lst[j]-1;
		if (a[i]==a[j]) 
		{
			lst[i]=j;
			f[i]=f[lst[i]-1]+1;
			ans+=f[i];
		}		
	}
	printf("%lld",ans);
	return 0;
}

Ehhh Ah


posted @ 2024-11-26 15:28  还是沄沄沄  阅读(16)  评论(1编辑  收藏  举报