NOIP2016提高A組8 11 自然數

2021-07-16 13:16:19 字數 1428 閱讀 1171

第一行n

第二行n個數

答案3

0 1 3

n<=

200000 a

i<=109

50分暴力明顯,用標記陣列隨便yy

但是你可能在想要離散化,其實凡是大於n的都直接等於n就行了,mex最大就是n

想:如果知道[1,n]的mex,能不能求到[2,n]

顯然mex[1,i]是單調遞增的,當第乙個數被刪掉時,如果後面原來比這個數大,並且在下乙個數出現之前,那就變成這個數

區間修改就可以用線段樹了

加上乙個線段樹上二分

線段樹初始化為mex[1,1],mex[1,2],mex[1,3]……一次修改變成mex[2,2],mex[2,3]……

修改n-1次,每次求和就行了

#include

#include

#include

#define fo(i,a,b) for(int i=a;i<=b;i++)

#define n 201000

#define ll long long

using namespace std;

int n,a[n],tot=0,bz[n],next[n];

ll ans=0;

struct note;

note t[n*25];

void down(int v,int i,int j)

void insert(int v,int i,int j,int

x,int

y,ll z)

intm=(i+j)/2;down(v,i,j);

if(y

<=m) insert(v*2,i,m,x,y,z);

else

if(x>m) insert(v*2+1,m+1,j,x,y,z);

else insert(v*2,i,m,x,m,z),insert(v*2+1,m+1,j,m+1,y,z);

t[v].m=max(t[v*2].m,t[v*2+1].m);t[v].h=t[v*2].h+t[v*2+1].h;

}int find(int v,int i,int j,ll x)

intm=(i+j)/2;down(v,i,j);

if(t[v*2].m>x) return find(v*2,i,m,x);

else

return find(v*2+1,m+1,j,x);

}int main()

fo(i,1,n) next[i]=(next[i]==0)?n+1:next[i];

fo(i,1,n-1)

printf("%lld",ans);

}

NOIP2016提高A組8 11 錢倉

發現,一定有乙個點作為起點,所有的路徑都不經過這個起點。接著貪心求答案,如果c i 1 將其中ci 1個錢往後 鋪 易證x 2 y2 x y 2 那麼維護乙個佇列,先進先出,就能保證最小。include include include include include include include ...

NOIP2016提高A組8 11 錢倉

發現,一定有乙個點作為起點,所有的路徑都不經過這個起點。接著貪心求答案,如果 c i 1 將其中 c i 1 個錢往後 鋪 易證 x 2 y 2 x y 2 那麼維護乙個佇列,先進先出,就能保證最小。include include include include include include in...

NOIP2016提高A組8 11 自然數

n 求出mex 1,i 1 i n 雖然0 ai 10 9,但只有n個數,所以mex一定小於等於n for long long j 1 j n j 顯然mex是單調不下降的,接著用線段樹維護mex。如果刪掉a i 從下乙個mex比a i 大的位置到下乙個a i 的位置之前的mex都會改變,都會變成a...