CF1246F Cursor Distance 题解

CF1246F Cursor Distance 题解


知识点

倍增。

分析

首先可以暴力建图跑全源最短路,时间复杂度 \(O(nm\log_2{(nm)})\)

那么这肯定行不通,我们尝试模拟找性质,假设现在尝试求出 \(\operatorname{dist}(i,j)\)

\(i\) 开始向 \(j\) 的方向前进,我们发现几乎没有什么规律可循,甚至还要考虑一些特殊情况,那么倒转方向:正难则反,从 \(j\) 开始向 \(i\) 的方向倒推,这时发现某个步数以内可达的所有 \(i\) 会变成一个连续的区间:

设对于点 \(i\),序列中在它左边、右边离它最近的字母相同的位置分别为 \(L_i,R_i\),如果没有则分别设为 \(1,n\)

那么对于一个 \(j\),一步以内可达它的 \(i\) 范围就是 \([L_j,R_j]\),那么在此基础上可以推出两步以内可以达到它的区间就是 \([\min_{k \in [L_j,R_j]}{L_k},\max_{k \in [L_j,R_j]}{R_k}]\),以此类推可以继续往更多步推广。

但是如何优化这个过程呢?\([L,R]\) 是互相关联的,更新不方便,那么我们尝试分开他们。

注意到小写字母只有 26(\(|\Sigma|\))个,放到这题里就是一个非常好的隐含性质。

考虑从 \([l,r]\) 往后再推一步到 \([l',r']\) 时,\(l\) 是如何到 \(l'\) 的:其实就是把 \([l,r]\) 中每种字母最右边那个拿出来,再取它们的 \(L\) 的最小值。那么对于每个 \([l,r]\) 中的 \(l\),由于原序列固定,我们只要按上面的方法推出 \(l’\),并按 \([l,r]\) 以内有几个不同种类的字符记下来,即可用不多的状态数涵盖所有情况。当然 \(R\) 部分也同理。

现在将 \([l,r]\) 的处理都分开了,考虑一次倍增最多会进行几次,中间由于字符种类数的变化,会将倍增分段,那么最多也就分成 \(|\Sigma|\) 段,每段 \(O(\log_2{n})\),那么时间复杂度就为 \(O(n|\Sigma|\log_2{n})\)

提示

倍增数组把小的一维放前面可能会快很多。

代码

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define CPY(a,b,c,d) memcpy(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
using namespace std;
constexpr int N(1e5+10),cN(25),cV(cN+1),lN(16),lV(lN+1);

char a[N];
int n;
int l[N],r[N];
int L[N][cV],R[N][cV],bL[N][cV],bR[N][cV],fL[lV][N],fR[lV][N];
ll ans;
ll pL[lV][N],pR[lV][N];

int main() {
	cin>>(a+1),n=strlen(a+1);
	FOR(i,0,cN)L[0][i]=1,R[n+1][i]=n;
	FOR(i,1,n) 
		CPY(L[i],L[i-1],L[i],1),L[i][a[i]-'a']=i,CPY(bL[i],L[i],bL[i],1),sort(bL[i],bL[i]+cV,greater<>());
	DOR(i,n,1) 
		CPY(R[i],R[i+1],R[i],1),R[i][a[i]-'a']=i,CPY(bR[i],R[i],bR[i],1),sort(bR[i],bR[i]+cV,less<>());
	FOR(i,1,n)l[i]=r[i]=i,fL[0][i]=n+1,fR[0][i]=0,pL[0][i]=i-1,pR[0][i]=n-i;
	FOR(w,0,cN) {
		FOR(i,1,n)tomin(fL[0][i],L[i-1][a[bR[i][w]]-'a']),tomax(fR[0][i],R[i+1][a[bL[i][w]]-'a']);
		FOR(j,1,lN)FOR(i,1,n) {
			fL[j][i]=fL[j-1][fL[j-1][i]],pL[j][i]=pL[j-1][i]+pL[j-1][fL[j-1][i]];
			fR[j][i]=fR[j-1][fR[j-1][i]],pR[j][i]=pR[j-1][i]+pR[j-1][fR[j-1][i]];
		}
		FOR(i,1,n) {
			DOR(j,lN,0) {
				const int &tl(fL[j][l[i]]),&tr(fR[j][r[i]]);
				if(w==cN||(1<tl&&tr<n&&bL[tr][w+1]<tl))
					ans+=pL[j][l[i]]+pR[j][r[i]],l[i]=tl,r[i]=tr;
			}
			if(w<cN&&1<l[i]&&r[i]<n&&bL[r[i]][w+1]<l[i])
				ans+=pL[0][l[i]]+pR[0][r[i]],l[i]=fL[0][l[i]],r[i]=fR[0][r[i]];
		}
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2025-01-05 14:43  Add_Catalyst  阅读(29)  评论(0)    收藏  举报