Luna likes Love 题解

\(\texttt {Problem Link}\)

简要题意

题目很清楚。

分析

定理

两个人中左边的人一直向右运动,和两人向中间走所用的步数相同

证明

假设有两组人为 \(a_l , a_r , b_l , b_r (a_l < a_r , b_l < b_r)\)

\(\textrm{I}.\)\(a_r < b_l\)(两者互不相交) 时

如图:

显然成立。

$ \textrm{II}.$ 当 $a_l < b_l < a_r < b_r $(两者相交) 时

如图:

假设先走 \(a\),此时 \(ans += a_r - a_l\)

再走 \(b\),此时 \(ans += b_r - b_l - 1\)(中间有一个 \(a_l\) 已经走完)。

最后 \(ans = (b_r - b_l) + (a_r - a_l) - 1\)

再考虑将 \(a\) 两端走到 \(b\) 之间的情况(略,和上面的方法一样)。

$ \textrm{III}.$ 当 \(a_l < b_l < b_r < a_r\)(两者包含)时

略(并不难证和情况 \(2\) 证明方法一样)。

综上,证明得证。

此时题目就很简单了。

最终实现

那么就可以贪心的让区间短的先走就行了(因为先走小的,大的区间距离会减小;反之,则不行)。

那就只需要用树状数组记录其中的已消失的数,统计答案时减去区间已消失的数。

code

#include <bits/stdc++.h>

using namespace std;
using ll = long long ;

const int N = 5e5 + 5 ;

int n;

struct REN{
	int first,last;
	int len;
	bool operator<(const REN&x)const{return len<x.len;}	
}p[N];

ll ans;

struct FenwickTree{
	private:
		ll t[N<<1];
		int lowbit(int x){return x&-x;}
	public:
		void add(int x,int val){for(;x<=n*2;x+=lowbit(x))t[x]+=val;}
		ll ask(int x){ll ans=0;for(;x;x-=lowbit(x))ans+=t[x];return ans;}
}t;

int main(){
	scanf("%d",&n);
	for(int i=1,x;i<=2*n;i++){
		scanf("%d",&x);
		if(!p[x].first)p[x].first=i;
		else p[x].last=i;
		p[x].len=p[x].last-p[x].first; // 记录区间长度和头和尾
	}
	
	sort(p+1,p+n+1);//贪心
	
	for(int i=1;i<=n;i++){
		ans+=p[i].len-t.ask(p[i].last)+t.ask(p[i].first-1);//减去已经消失的
		t.add(p[i].first,1);
		t.add(p[i].last,1);// 记录这个人已经消失
	}
	printf("%lld",ans);
	return 0;
}
posted @   Z_drj  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示