“May you, the beauty of this world, always shine.”

P17833

前言

笑点解析:

if(Le[i+1] == Le[i]) vL += valL[Le[i+1]];
if(Ri[i+1] == Ri[i]) vR += valR[Ri[i]];

赛时代码对于 valL 和 valR 的处理加上这个即可过。痛失 WC。

思路

其实是比较简单的题,所以为什么出题人要在大样例里塞 Corner Case 哦哦哦。

首先注意到方案数为 2 的充要条件当且仅当对于一个点对 \((u,v)\),\(u \to v\) 和 \(v \to u\) 贪心的跳只差一个点。我们容易处理出向左跳和向右跳的极限点,分别记为 \(l,r\),则我们容易对于每一个前缀和后缀,得到前后极限跳方案唯一的路径数量。

然后我们同时不难发现这个不同点是相邻的,否则会有 >2 条路径,显然不合法。然后我们可以枚举这对不同点。但是这里还有一个我赛时没有想到的要求,就是说只有这对相邻点的的向左的极限跳相等,才能继承 \(l\) 的贡献,对于向右的也是同理,否则你无法通过大样例4。考虑如果极限跳不相等,而两点又在路径上,则显然可以更换跳点,形成 >2 条路径。注意到我的做法的证明依赖于这个,但是犯糖导致以为这个会自动合法。

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 2e6 + 10;
int n; LL d;
LL x[N];
int Le[N],Ri[N];
LL valL[N],valR[N];
void solve(){
	cin >> n >> d;
	for(int i=1;i<=n;i++)
		cin >> x[i];
	int L=1;
	for(int i=1;i<=n;i++){
		while(L < i && x[i] - x[L] > d) L ++ ;
		Le[i] = L;
	}
	int R = n;
	for(int i=n;i>=1;i--){
		while(R > i && x[R] - x[i] > d) R -- ;
		Ri[i] = R;
	}
	for(int i=1;i<=n;i++){
		if(Le[i] == Le[i+1]) valL[i] = 0;
		else valL[i] = valL[Le[i]] + (Le[i+1] - Le[i]);
	}
	for(int i=n;i>=1;i--){
		if(Ri[i] == Ri[i-1]) valR[i] = 0;
		else valR[i] = valR[Ri[i]] + (Ri[i] - Ri[i-1]);
	}
	LL ans = 0;
	for(int i=2;i<n-1;i++){
		if(Le[i+1] >= i || Ri[i] <= i + 1) continue;
		LL vL,vR;
		vL = min(Le[i+2],i) - Le[i+1];
		vR = Ri[i] - max(i+1,Ri[i-1]);
		if(vL == 0 || vR == 0) continue;
		if(Le[i+1] == Le[i]) vL += valL[Le[i+1]];
		if(Ri[i+1] == Ri[i]) vR += valR[Ri[i]];
		ans += vL * vR;
	}
	cout << ans << "\n";
}
int main(){
	IOS;
	int c,T;
	cin >> c >> T;
	while(T -- )
		solve();
	return 0;
}

Fun Fact

什么叫我的左边是 jiazhichen844?

posted @ 2026-11-01 15:32  WinterXorSnow  阅读(3)  评论(0)    收藏  举报