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\),有状态转移方程:
现在考虑怎么求\(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