我看沒人寫這題題解,那本菜雞來寫一下
題意:
給長度為n的序列,m次詢問,每次詢問區間 [l,思路:r]
[l,r]
[l,r
]中有多少數符合該數出現的個數等於它本身
這題的題意非常符合莫隊演算法
莫隊演算法的時間複雜度是o(n
sqrt
(n))
o(nsqrt(n))
o(nsqr
t(n)
),所以如果常數很大的話,會tle,但這題的資料量才1e5
1e51e
5開跟後也不是很大,所以用莫隊解決很輕鬆。
莫隊演算法的主要思想其實就是區間移動,舉個栗子:
假如a陣列有5
55個數:[1,
2,3,
4,5]
[1, 2, 3, 4, 5]
[1,2,3
,4,5
],我們知道[2,
3]
[2,3]
[2,3
]區間的和為5,呢麼我們想求[1,
4]
[1,4]
[1,4
]區間的和怎麼辦? 明顯我們把已知區間通過擴大或者縮小左右邊界就能得到我們想要的值 sum
([1,
4])=
sum(
sum[
2,3]
+a[−
−l]+
a[++
r]
)sum([1,4])=sum(sum[2,3]+a[--l]+a[++r])
sum([1
,4])
=sum
(sum
[2,3
]+a[
−−l]
+a[+
+r])
,但是有乙個坑點,就是如果我們詢問的區間之間的間隔很大,呢麼時間複雜度就炸了,舉個栗子:我們第一次要詢問[1,
1]
[1,1]
[1,1
]區間的和,第二次詢問[n,
n]
[n,n]
[n,n
],第三次詢問[1,
1]
[1,1]
[1,1
]…詢問m次,呢麼每次移動從[1,
1]
[1,1]
[1,1
]移動到[n,
n]
[n,n]
[n,n
],就要移動2*n次,呢麼m次詢問就是o(n
∗m
)o(n*m)
o(n∗m)
,肯定頂不住了,呢麼莫隊演算法就解決了這個問題,從而把時間複雜度優化到了o(n
sqrt
(n))
o(nsqrt(n))
o(nsqr
t(n)
),其實原理很簡單,就是排序,把區間排個序,這樣就不會出現上面那種情況了,這也是莫隊操作強制離線的原因。我們只需要記錄求的區間的id,把答案按照原序輸出即可
莫對區間的排序:
排序才是莫隊演算法的精髓,而且這個需要用到分塊,如果想細緻了解的話就去看看分塊,如果不想細緻了解,就記住排序的方式,這也是莫隊被人稱為板子的原因,因為莫隊除了寫出增縮區間的策略,其他的其實一毛一樣。
排序的方式:
如果詢問區間的l在同乙個塊中,就按照詢問區間的r排序從小到大的序,如果不在同乙個塊中,就按照l所在塊的大小,從小到大排序為什麼這樣排:
其實很簡單,優先排l所在塊小的這樣,我們把l塊小的增縮完後,就不會在回到塊小的,同理在同一塊中按照r小的排,把r小的增縮完後,他就不會在回到後面了,而是往前,這也時間複雜度也就o(n講完這個,這題就很簡單了,我們只需要考慮增縮的方案,首先我們如果要往區間中加貢獻,呢麼我們只需要考慮當前的a[i]的值於它的個數之間的關係,如果本身等於,呢麼我們加後,這個區間的答案就由上個區間的答案–,如果++後等於a[i]的值,呢麼這個區間的答案就有上個區間的答案++,同理減貢獻也一樣+m
)o(n+m)
o(n+m)
這題的話需要離散化,因為數很大,而且離散化後數的數量並不影響結果,所以可以使用離散化,而且map會t,因為在增縮操作是o(n
+m
)o(n+m)
o(n+m)
這樣導致的時間複雜度是o(n
+m)l
og
no(n+m)logn
o(n+m)
logn
,所以我們可以另開乙個陣列進行輔助,這也就可以把時間複雜度降到o(n
logn
)o(nlogn)
o(nlog
n)其實1e5這個資料量剛好被莫隊水過了,如果資料量再大一點,就不行了,這也是上面為什麼不能用map的原因,可以算一下1e5
∗sqr
t(1e
5)=2
e7
1e5*sqrt(1e5)=2e7
1e5∗sq
rt(1
e5)=
2e7,剛剛好蹭著時間複雜度的邊過,很危險
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const
int inf =
1<<30;
const
int maxn =
1e5+5;
typedef long
long ll;
const
int n =
5005
;int dp[n]
, ans[maxn]
;struct node
p[maxn <<1]
;int pos[maxn]
, vis[maxn]
;vector<
int>
vec;
intgetid
(int x)
bool cmp
(node a, node b)
int res, a[maxn]
, b[maxn]
;void
add(
int i)
void
sub(
int i)
intmain()
sort
(p, p + q, cmp)
;int l =
1, r =0;
for(
int i =
0; i < q; i++
)for
(int i =
0; i < q; i++
)printf
("%d\n"
, ans[i]);
}
2020NYIST個人積分賽第二場 A
疫情當下,有兩個很無聊的人,小a和小b,準備玩乙個遊戲,玩法是這樣的,從兩個自然數開始比賽。第乙個玩家小a從兩個數字中的較大者減去兩個數字中較小者的任何正倍數,前提是得到的數字必須是非負的。然後,第二個玩家小b對得到的兩個數字做同樣的處理,兩個玩家交替進行,直到乙個玩家能夠從大的數字中減去較小數字的...
2020NYIST個人積分賽第四場 F
原題鏈結 hihocoder 1032 就是最長回文子串 sample input 3abababa aaaabaa acacdas sample output75 3以某個位置為中心位置,向兩邊擴充套件判斷是否是回文串,再判斷是否為最長回文串 注意邊界處理 include include incl...
2020NYIST個人積分賽第六場 D
題意 給n個點,m條邊,讓構建乙個有向無環無重邊的圖,並且圖的最短路是素數,最小生成樹也是素數。思路 題意的可塑造性很強,我們可以讓最小生成樹就是最短路,呢麼我們現在就是給最小生成樹找乙個素數,很明顯最小生成樹的素數範圍在 1,1e14 1,1e14 1,1e1 4 所以預處理1 1e14不太可能,...