Soratosorato

P9310 Luna likes Love 题解

Sorato·2023-10-15 19:54·16 次阅读

P9310 Luna likes Love 题解

原题:[洛谷P9310]([P9310 EGOI2021] Luna likes Love / 卢娜爱磕 cp - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))

题目大意#

给定一个长度为 2n(n105) 的序列,序列中 1n 的每一个数都恰好出现两次。

可进行两种操作:

  1. 交换两个相邻的数的位置。
  2. 若两个相邻的数相同,则删去这两个数。

问最少进行多少次操作可使序列为空。

思路#

显然对于序列中一个在前面出现过的数 ai,我们应该把它交换到与它上一次出现的位置 lstai 相邻,并删掉它们,那么代价就是 它们之间剩余的数的数量 +1

暴力的话,用 visi 标记第 i 个数是否已被删去。如果 ai 在前面出现过,那么让 ans 加上 j=lstaiivisj+1,然后让 visi=vislstai=1

考虑优化。我们可以开一个前缀和数组 sumi,表示前 i 个数里被删去的数的个数。带修,所以用树状数组。那么上面的操作可以变为:让 ans 加上 ilstai1+1sumi+sumlstai,并 add(i,1),add(lstai,1)

Code#

Copy
#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; }
posted @   Sorato  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
目录