牛半仙有 n 個妹子,魅力值分別為 1 ~ n,排成一排。官網給的題解看不懂 看到有大佬說 cdq 分治可以做 然後又看不懂大佬的 cdq 於是就自己歪歪了乙個常數巨大的 o(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_
vj1
,且不存在乙個 j 使得p
i<
j
+1
p_i < j < p_
pi<
j+1,vpi
i+
1v_ < v_j < v_}
vpi
i+1
。牛半仙想知道他有多少種選出完美妹子序列的方式。
因為牛半仙忙著和妹子玩耍,所以他想你幫他解決一下問題。
方法數可能很多,牛半仙只想知道對 998244353 取模的結果。
log2n
)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 sjsi 然後前部分的 pos jpos_j posj 又是上公升的 pos 就是初始位置 考慮條件 3 如果 j 對 i 有貢獻 那麼 j 在 i 對應的我們上面說的那個區間中 且區間中 j 的後面沒有價值比它大的點 所以對 i 有貢獻的點形成的就是乙個下降的序列 且屬於這個區間 所以可以在每個前部分的點上 維護乙個序列 滿足序列中從這個點往前走價值都是上公升的 (顯然我們不需要存具體哪些點 只需要存貢獻和) 考慮還有後部分的點的限制呢 如果在後部 i 的前面有乙個價值比它小的點 x 那麼對 i 有貢獻的點的 pos 必須大於 x 的 pos 於是區間的就不是字首區間了 但是我們維護的序列都是從第乙個數開始的 咋辦 其實就是減去前面的貢獻就行了 這個區間的下降序列的第乙個點 一定是價值最大的那個點 所以用區間最後乙個點的序列貢獻 減去區間序列中第乙個點維護的序列貢獻 再加上它自己的貢獻 我們要求的了 yzxx大佬給了個新思路 然後下午和機房的人討論出了個乙個 log 的做法 網上也沒有 我覺得那是最好理解的乙個 相信 yzxx 大佬一定會寫部落格的 #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 大的妹子的名字。如果出現... 點此看題 考試時候先打了個表,首先我們可以確定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是定值,打表如下 資料...#include
牛半仙的妹子序列
牛半仙的妹子串
nowcoder 2020 牛半仙的妹子數