6691. 2020.06.05省选模拟六道剑「一念无量劫」
Posted gmh77
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6691. 2020.06.05省选模拟六道剑「一念无量劫」相关的知识,希望对你有一定的参考价值。
题目描述
妖梦在练习剑术
有 n 个木桩排成一排,从左到右高度分别为 h 1 ,h 2 ,h 3 ,...,h n ,这些高度两两不同
妖梦每次可以选择两个相邻的木桩交换,这样的交换可以进行任意多次
妖梦也可以使用符卡:选择两个木桩交换,但最多只能使用一次。
妖梦想要知道将木桩排成从左到右递增的顺序,她最少需要进行多少次交换。
题解
log^3能过60000
如果i要作为左端点的话必须不能有j满足j<i且a[j]>a[i],右端点类似
那么可以找出可能的单调左右端点,原来的每个点的影响范围都可以在上面对应两段区间,建成坐标系就是一个矩形
扫描线即可
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
#define file
using namespace std;
struct type{int x1,x2,y,s;} d[600001];
int a[300001],tr[1200001][2],Tr[1200001],b[300001],c[300001],n,i,j,k,l,r,mid,t1,t2,tot,find1,find2,X1,X2,Y1,Y2;
bool bz[300001];
ll ans,Ans;
void down(int t,int len)
{
if (Tr[t])
{
if (len>1) Tr[t*2]+=Tr[t],Tr[t*2+1]+=Tr[t];
tr[t][0]+=Tr[t]*len,tr[t][1]+=Tr[t];
Tr[t]=0;
}
}
void up(int t,int len)
{
tr[t][0]=tr[t*2][0]+Tr[t*2]*((len+1)/2)+tr[t*2+1][0]+Tr[t*2+1]*(len/2);
tr[t][1]=max(tr[t*2][1]+Tr[t*2],tr[t*2+1][1]+Tr[t*2+1]);
}
void change(int t,int l,int r,int x,int y,int s)
{
int mid=(l+r)/2;
down(t,r-l+1);
if (x<=l && r<=y) {Tr[t]+=s;down(t,r-l+1);return;}
if (x<=mid) change(t*2,l,mid,x,y,s);
if (mid<y) change(t*2+1,mid+1,r,x,y,s);
up(t,r-l+1);
}
void find(int t,int l,int r,int x,int y)
{
int mid=(l+r)/2;
down(t,r-l+1);
if (x<=l && r<=y) {find1+=tr[t][0],find2=min(find2,tr[t][1]);return;}
if (x<=mid) find(t*2,l,mid,x,y);
if (mid<y) find(t*2+1,mid+1,r,x,y);
}
void add(int X1,int X2,int Y1,int Y2) {d[++tot]={X1,X2,Y1,1};d[++tot]={X1,X2,Y2+1,-1};}
bool cmp(type a,type b) {return a.y<b.y;}
int main()
{
freopen("sword.in","r",stdin);
#ifdef file
freopen("sword.out","w",stdout);
#endif
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i]);
fd(i,n,1) find1=find2=0,find(1,1,n,1,a[i]),Ans+=find1,change(1,1,n,a[i],a[i],1);
fd(i,n,1){while (t1 && a[i]>a[b[t1]]) --t1;b[++t1]=i;}
fo(i,1,n) {while (t2 && a[i]<a[c[t2]]) --t2;c[++t2]=i;}
fo(i,1,t1) bz[b[i]]=1;
fo(i,1,t2) bz[c[i]]=1;
fo(i,1,n)
if (!bz[i])
{
l=1;r=t1;
while (l<r)
{
mid=(l+r)/2;
if (b[mid]>i) l=mid+1; else r=mid;
}
X1=l;
l=1;r=t1;
while (l<r)
{
mid=(l+r)/2;
if (a[b[mid]]>a[i]) l=mid+1; else r=mid;
}
X2=l-(a[b[l]]<a[i]);
l=1;r=t2;
while (l<r)
{
mid=(l+r)/2;
if (c[mid]<i) l=mid+1; else r=mid;
}
Y1=l;
l=1;r=t2;
while (l<r)
{
mid=(l+r)/2;
if (a[c[mid]]<a[i]) l=mid+1; else r=mid;
}
Y2=l-(a[c[l]]>a[i]);
add(X1,X2,Y1,Y2);
}
if (tot>0)
{
memset(tr,0,sizeof(tr));
memset(Tr,0,sizeof(Tr));
sort(d+1,d+tot+1,cmp);
fo(i,1,tot)
{
change(1,1,n,d[i].x1,d[i].x2,d[i].s);
if (i==tot || d[i].y!=d[i+1].y) down(1,n),ans=max(ans,tr[1][1]);
}
}
printf("%lld
",Ans-ans*2);
fclose(stdin);
fclose(stdout);
return 0;
}
以上是关于6691. 2020.06.05省选模拟六道剑「一念无量劫」的主要内容,如果未能解决你的问题,请参考以下文章
JZOJ 6693. 2020.06.05省选模拟紫色彼岸樱推迟绽放 (自然数幂拆上升幂+组合意义矩阵乘法+NTT)