牛半仙的妹子序列

2021-10-10 12:16:55 字數 3934 閱讀 9623

牛半仙有 n 個妹子,魅力值分別為 1 ~ n,排成一排。

牛半仙會在這些妹子中選若干個,但是他很 貪婪,他只會選完美妹子序列。

乙個妹子序列 (p

ip_i

pi​指妹子的位置)是完美的,當且僅當其是一 個上公升序列,且不存在乙個 j,使得j

>pm

j > p_m

j>pm

​且 v

j>vp

mv_j > v_

vj​>vp

m​​,且不存在乙個 j 使得 j

j< p_1

j​且 v

j

1v_j < v_

vj​1​

​,且不存在乙個 j 使得p

i<

j

+1

p_i < j < p_

pi​<

j+1​,vpi

i+

1v_ < v_j < v_}

vpi​

​​i+1​

​ 。牛半仙想知道他有多少種選出完美妹子序列的方式。

因為牛半仙忙著和妹子玩耍,所以他想你幫他解決一下問題。

方法數可能很多,牛半仙只想知道對 998244353 取模的結果。

官網給的題解看不懂 看到有大佬說 cdq 分治可以做 然後又看不懂大佬的 cdq 於是就自己歪歪了乙個常數巨大的 o(n

log⁡2n

)o(n\log^2n)

o(nlog2n

) 的 cdq

首先可以想到乙個 dp 的做法

f if_

fi​ 表示以 i 為結尾的方案數 那麼可以貢獻到 i 的 j 滿足條件

j

jj

v_jvj

​​區間 (j,

i)

(j,i)

(j,i

) 不存在價值在他們之間的數 o(n

2)

o(n^2)

o(n2

) 可以 dp 直接求

考慮 cdq 分治

我們把價值拿來分治(這裡最關鍵 用下標分治就不行

cdq 分治的過程是求前半部分對後半部分的貢獻 於是我們這裡求的就是 價值在 [l,

mid]

[l,mid]

[l,mid

] 的妹子 對價值在 [mi

d+1,

r]

[mid+1,r]

[mid+1

,r] 的妹子的貢獻

那麼在分治過程中 前半部分的點就滿足了條件 2

在 merge 求對後半部分的貢獻時候 我們對前後兩部分的妹子分別按初始順序排序

這是為了滿足條件 1

如果只考慮條件 1

2 這時對後部分的點 i 有貢獻的點 就成了前部分的乙個字首區間

因為對前部分的點要求多了乙個 pos

j

si

pos_jpo

sj​si

​ 然後前部分的 pos

jpos_j

posj

​ 又是上公升的 pos 就是初始位置

考慮條件 3

如果 j 對 i 有貢獻

那麼 j 在 i 對應的我們上面說的那個區間中 且區間中 j 的後面沒有價值比它大的點

所以對 i 有貢獻的點形成的就是乙個下降的序列 且屬於這個區間

所以可以在每個前部分的點上 維護乙個序列 滿足序列中從這個點往前走價值都是上公升的 (顯然我們不需要存具體哪些點 只需要存貢獻和)

考慮還有後部分的點的限制呢 如果在後部 i 的前面有乙個價值比它小的點 x

那麼對 i 有貢獻的點的 pos 必須大於 x 的 pos 於是區間的就不是字首區間了 但是我們維護的序列都是從第乙個數開始的 咋辦

其實就是減去前面的貢獻就行了 這個區間的下降序列的第乙個點 一定是價值最大的那個點

所以用區間最後乙個點的序列貢獻 減去區間序列中第乙個點維護的序列貢獻 再加上它自己的貢獻 我們要求的了

yzxx大佬給了個新思路 然後下午和機房的人討論出了個乙個 log 的做法 網上也沒有 我覺得那是最好理解的乙個 相信 yzxx 大佬一定會寫部落格的

#include

#define n 200005

#define lson rt<<1,l,mid

#define rson rt<<1|1,mid+1,r

#define mid ((l+r)>>1)

using

namespace std;

typedef

long

long ll;

const ll mod=

998244353

;const

int inf=

1e9;

int n,cnt,a[n]

,lst[n]

,t[n]

;ll anss,sum[n]

;bool tag[n]

;struct nodecc[n]

;bool

cmp_val

(node x,node y)

bool

cmp_pos

(node x,node y)

struct sl_tree

else

}int

query

(int l,

int r,

int rt=1,

int l=1,

int r=cnt)

int x=

0,y=0;

if(l<=mid)x=

query

(l,r,lson);if

(r>mid)y=

query

(l,r,rson);if

(a[x]

>a[y]

)return x;

return y;

}void

build

(int rt=1,

int l=1,

int r=cnt)

build

(lson)

;build

(rson)

;push_up

(rt);}

}tr;

void

merge

(int l,

int r)

tr.build()

; now=0;

for(

int i=mid+

1;i<=r;i++

)for

(int i=mid+

1;i<=r;i++)}

void

cdq(

int l,

int r)

cdq(l,mid)

;sort

(cc+mid+

1,cc+r+

1,cmp_pos)

;merge

(l,r)

;sort

(cc+mid+

1,cc+r+

1,cmp_val)

;cdq

(mid+

1,r)

;sort

(cc+l,cc+r+

1,cmp_pos);}

intmain()

sort

(cc+

1,cc+

1+n,cmp_val)

;cdq(1

,n);

int now=0;

for(

int i=n;i>=

1;i--)if

(cc[i]

.v>now)anss=

(anss+cc[i]

.ans)

%mod,now=cc[i]

.v; cout<}

牛半仙的妹子序列

傳送門 to nowcoder 不妨把題目中的 魅力值 叫做 a langle a rangle a 用 d p tt dp dp,轉移條件比較苛刻。如果 f j f j f j 能轉移到 f i f i f i 需要滿足 只關注不超過a ia i ai 的數時,aj aj a j a jaj aj...

牛半仙的妹子串

operatorname nowcod er21 2921 點我可以檢視其它題目 目錄 點我跳轉 題目描述 牛半仙有 n n n 個妹子。牛半仙用對於每個妹子都有乙個名字,並且給了每個妹子乙個評分。牛半仙的審美與名字有關,他想知道名字以某字母結尾的妹子中,評分第 k k k 大的妹子的名字。如果出現...

nowcoder 2020 牛半仙的妹子數

點此看題 考試時候先打了個表,首先我們可以確定a b ca b c a b c是乙個定值,一開始我想去維護a aa和b bb然後去算c cc,但是這樣會很難算,a aa和b bb的變化是極不規律的,我們不妨去研究ccc 在重複一遍,p a b c p a b c p a b c是定值,打表如下 資料...