P9310 Luna likes Love 题解
原题:[洛谷P9310]([P9310 EGOI2021] Luna likes Love / 卢娜爱磕 cp - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))
题目大意#
给定一个长度为 的序列,序列中 的每一个数都恰好出现两次。
可进行两种操作:
- 交换两个相邻的数的位置。
- 若两个相邻的数相同,则删去这两个数。
问最少进行多少次操作可使序列为空。
思路#
显然对于序列中一个在前面出现过的数 ,我们应该把它交换到与它上一次出现的位置 相邻,并删掉它们,那么代价就是 它们之间剩余的数的数量 。
暴力的话,用 标记第 个数是否已被删去。如果 在前面出现过,那么让 加上 ,然后让 。
考虑优化。我们可以开一个前缀和数组 ,表示前 个数里被删去的数的个数。带修,所以用树状数组。那么上面的操作可以变为:让 加上 ,并 。
Code#
#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define reg register
#define int long long
using namespace std;
inline int read()
{
short f=1;
int x=0;
char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
int n,a,ans,c[1000010],lst[500010];
inline void add(int x) {for(;x<=2*n;x+=x&-x) c[x]=-~c[x];}
inline int ask(int x) {int ans=0; for(;x;x-=x&-x) ans+=c[x]; return ans;}
signed main()
{
n=read();
for(reg int i=1;i<=2*n;i=-~i)
{
a=read();
if(lst[a])
ans+=i-lst[a]-ask(i)+ask(lst[a]),add(lst[a]),add(i);
lst[a]=i;
}
return printf("%lld",ans),0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】