0%

思路讲解

主要参考这段代码

https://github.com/algorithmzuo/algorithm-journey/blob/main/src/class157/Code02_PointPersistent2.java

参考题解

【算法讲解157【挺难】可持久化线段树和标记永久化】 【精准空降到 45:11】 https://www.bilibili.com/video/BV1bSc6eREi4/?share_source=copy_web&vd_source=6ca0bc05e7d6f39b07c1afd464edae37&t=2711

AC代码

https://www.luogu.com.cn/record/218615977

心路历程(WA,TLE,MLE……)

https://www.luogu.com.cn/record/218612872

这个 k-lsum 要小心,记得要加,因为往r走相当于抛掉了一些东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// u v 为node,l,r为区间,k为区间第k小
int query(int u,int v,int l,int r,int k){
if(l==r){
return l;
}
// 我们这样就知道了
int lsum=sum[ls[v]]-sum[ls[u]];
int mid=l+r>>1;
if(lsum>=k){
return query(ls[u],ls[v],l,mid,k);
}else{ // 这个 k-lsum 要小心,记得要加,因为往r走相当于抛掉了一些东西
return query(rs[u],rs[v],mid+1,r,k-lsum);
}
}

思路讲解

子序列自动机,最重要的是next数组,可以找到从i位置开始,字符下一次出现在哪个位置(下标)(包括i位置)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct seqAuto{	// 子序列自动机 subsequence automaton 
// 可以处理大小写字母,数字,但是可能要改一下base以及next
vector<vector<int>> next;
// 从i位置开始,字符下一次出现在哪个位置(下标)(包括i位置)
char base='a';
seqAuto(const string &s){
next.assign(SZ(s)+5,vector<int>(28,-1));
ROF(i,SZ(s)-1,0){
FOR(j,0,26){
next[i][j]=next[i+1][j];
}
next[i][s[i]-base]=i;
}
}
inline bool isFind(const string &s){ // 传入substr时,必须为const属性
ll idx=0;
FOR(i,0,SZ(s)-1){
if(next[idx][s[i]-base]!=-1){
idx=next[idx][s[i]-base]+1;
}else{
return false;
}
}
return true;
}
};

然后用双指针方式枚举子串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FOR(i,0,SZ(S)-1){	// 双指针
FOR(j,bp,SZ(S)){
assert(j>=i);
ll len=j-i;
if(!sat.isFind(S.substr(i,len))){ // pos,len
bp=j;
if(ans.empty() || len-1>SZ(ans.back())){
ans.clear();
ans.pb(S.substr(i,len-1));
}else if(len-1==SZ(ans.back()) ){
ans.pb(S.substr(i,len-1));
}
break;
}
}
}

AC代码

https://www.luogu.com.cn/record/218545124

心路历程(WA,TLE,MLE……)

思路讲解

使用递推方法加快Sum预处理速度。

image

递推代码。

1
2
3
4
5
6
7
8
ROF(k,log2(N)-1,0){  // 
FOR(i,0,pow2[k]-1){
// assert(pow2[k]+i<SZ(Sum[k+1]));
Sum[k][i]=Sum[k+1][i]+Sum[k+1][pow2[k]+i];
Sum[k][i]%=mod;
Cnt[k][i]=Cnt[k+1][i]+Cnt[k+1][pow2[k]+i];
}
}

AC代码

https://www.luogu.com.cn/record/218505364

心路历程(WA,TLE,MLE……)

赛时因为没有采用递推所以代码比较慢。

思路讲解

赛时稍微有点暴力,其实这个是增长的,递增的(不要从代数上想,从几何的角度想就容易很多)。

那么二分或者是双指针都行,那我们就写一个双指针吧,好久没写了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 双指针做法
FOR(i,1,N-1){
FOR(j,bp,N){
ll curArea=Sum[j-1]-Sum[i-1];
ll ldiff=Sum[N]-curArea*2; // ldiff不能加abs,只要ldiff变为负数了,继续加j一定会变大
if(ldiff>=0){
ans=min(ans,abs(ldiff));
}else{
ans=min(ans,abs(ldiff));
bp=j;
break;
}
}
}

核心做法如上,最重要的就是ldiff不能加abs,只要 ldiff 变为负数了,继续加 j 一定会变大(绝对值)。

AC代码

https://www.luogu.com.cn/record/218460139

心路历程(WA,TLE,MLE……)

https://www.luogu.com.cn/record/218309162

赛时TLE,也骗到了80分,可以了可以了。