1. 程式人生 > >JZOJ 5947. 【NOIP2018模擬11.02】初音未來

JZOJ 5947. 【NOIP2018模擬11.02】初音未來

題目

Hercier作為一位喜愛Hatsune Miku的OIer,痛下決心,將Vocaloid買回了家。開啟之後,你發現介面是一個長為n的序列,代表音調,並形成了全排列。你看不懂日語,經過多次嘗試,你只會用一個按鈕:將一段區間按升序排序。不理解音樂的Hercier決定寫一個指令碼,進行m次操作,每次對一段區間進行操作。可惜Hercier不會寫指令碼,他找到了在機房裡的你,請你模擬出最後的結果。

資料範圍 在這裡插入圖片描述

題解

70分做法: O(mlog2n)O(m\ log^2n) 40分送的。 測試點3-7,直接就二分答案就好了。變成只有0和1組成的序列。 O(nm)O(nm)桶排,同樣能拿到70分。 100分: 抓住重點:考慮氣泡排序與逆序對的關係。如果一段序列沒有逆序對,那麼可以不理之。 一種水法,暴力桶排,修改b[i]的字首和s[i]。 b[i]表示a[i]和a[i-1]是否構成逆序對(0/1) 如果s[r]=s[l],那麼操作[l,r]無用。 迴圈展開一下即可。 正解: 逆序對不超過n

(n1)2\frac{n(n-1)}{2}個。 如果一段序列沒有逆序對,那麼可以不理之。 維護一個線段樹,對勢能分析整體感知,看似暴力的方法,實際上是能過的。 線段樹維護b[i] 如果每次找到最左邊的逆序對所在的位置x,經過一些修改,使得[l,x]這段區間變得有序,那麼不是做完了嗎? 反正最多隻會被交換O(n2)O(n^2)次。

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 1510 #define Min(x,y) ((x)<(y)?(x):(y)) #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; bool tr[N<<2]; bool la[N<<2]; int i,j,k,l,r,n,m,ans; int L,R,opl,opr,opx,opz; int vl,vr,Mid; int a[N],b[N]; int read(){ int fh=0,rs=0;char ch=0; while((ch<'0'||ch>'9')&&
(ch^'-'))ch=getchar(); if(ch=='-')fh=1,ch=getchar(); while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar(); return fh?-rs:rs; } void Swap(int &x,int &y){ x=x^y; y=x^y; x=x^y; } void downld(int ps){ if(la[ps]){ tr[ps<<1]=tr[(ps<<1)|1]=0; la[ps<<1]=la[(ps<<1)|1]=1; la[ps]=0; } } void build(int ps,int l,int r){ if(l==r){ tr[ps]=(a[l]<a[l-1]); return; } int wz=(l+r)>>1; build(ps<<1,l,wz); build((ps<<1)|1,wz+1,r); tr[ps]=tr[ps<<1]|tr[(ps<<1)|1]; } void change(int ps,int l,int r){ if(l==r){ tr[ps]=1; return; } downld(ps); int wz=(l+r)>>1; if(opx<=wz)change(ps<<1,l,wz); else change((ps<<1)|1,wz+1,r); tr[ps]=tr[ps<<1]|tr[(ps<<1)|1]; } void doit(int ps,int l,int r){ if(!tr[ps])return; if(l==r){ int i,j; for(j=l;j<=opr&&a[j]<a[j-1];j++) for(i=j;i>opl&&a[i]<a[i-1];i--)Swap(a[i],a[i-1]); return; } downld(ps); int wz=(l+r)>>1; doit(ps<<1,l,wz); doit((ps<<1)|1,wz+1,r); } void query(int ps,int l,int r){ if(!tr[ps])return; if(opl<=l&&r<=opr){ doit(ps,l,r); la[ps]=1;tr[ps]=0; return; } downld(ps); int wz=(l+r)>>1; if(opl<=wz)query(ps<<1,l,wz); if(opr>wz)query((ps<<1)|1,wz+1,r); } int main(){ n=read();m=read();L=read();R=read(); fo(i,1,n)a[i]=read(); build(1,1,n); fo(i,1,m){ opl=read(),opr=read(); query(1,1,n); if(a[opl]<a[opl-1]){ opx=opl; change(1,1,n); } if(a[opr+1]<a[opr]){ opx=opr+1; change(1,1,n); } } fo(i,L,R)printf("%d ",a[i]); return 0; }