YZOJ P3290 暴力 性質題

2021-08-09 13:13:07 字數 3385 閱讀 9584

鏈結

題意描述

給定乙個h×

w 的網格圖,m個互不相交(定義相交為:∃a

∈rec

a,a∈

recb

且 ∃a

∈rec

a,a∉

recb

)的矩形,n個點對。

當兩點可以不經過矩形相互到達時,稱這個點對合法。

求合法的點對數。

題解

最初的想法就是連線合法邊,對於乙個點dfs一遍,對可以到達的點用並查集維護為乙個集合,這個做法複雜度大概o(hw),姿勢正確的話有60分。

我們可以發現乙個性質。由於矩形互不相交,則:

如果兩個點屬於的最小的矩形相同,則兩個點一定可以連通。

且易證其為充要條件。

於是我們就可以算出兩個點的最小包含矩形,並判斷它們是否相等即可。

這個做法時間複雜度為o(nm)。雖然常數優化了不少,**難度也瞬間下降為普及組第一題,但依然只有60分。

在真正的賽場上,除了想到正解,想到一中易於實現的做法也是乙個成功。採用相對容易的演算法,時間還是風險都有所下降。

這個演算法的瓶頸在計算最小矩形的時間,每做一次都要花費o(m)的時間,一看就很有優化的空間!我們如何用更優秀的時間算出每個點所屬的矩形呢?

最小矩形作為乙個集合元素,不易於代數的描述和記錄。我們嘗試改變表示方法,這就要求我們找出屬於同乙個最小矩形的點的通性,即乙個條件p,作為兩個點屬於同乙個最小矩形的充要條件。

如果給每乙個矩形隨機乙個編號,對包含其的所有矩形的編號以某種方法求乙個雜湊值,不就可以唯一的表示這些點了嗎?

想法很好!接著我們就可以開始優化了。

優化o(m)時間的很常用的做法就是記字首和。然而,一維的字首和是對於一一維的線而言的。對於二維的平面,我們需要對其分治,這也決定了它無法達到一維o(1)效率的轉移,而需要o(log_n)。

這個時候我們遇到了難以逾越的障礙,因為我們很難確定乙個排序的方法,自然也就無法分治秋字首和。

我們發現,「包含」是個不易表示的概念。有沒有辦法用其他方式表示這個概念呢?

對於綠點,屬於矩形p1,在其左上角所包含的區域裡面,有p1的點奇數個,p2、p3的點偶數個。

對於粉點,屬於矩形p1、p2,在其左上角包含p1、p2的點奇數個,p3的點偶數個。

規律很明顯,也易證明。

看到奇偶性我們很容易想到異或操作的性質。我們對於每乙個矩形的四個點隨機乙個雜湊值,就可以表示每乙個,對乙個要求的點的左上方位置的所有端點取乙個異或和作為雜湊值,就可以很大概率唯一的表示此點和此點所屬點集的位置關係了。

我們就是希望將乙個個複雜的矩形轉化乙個個簡單的點,化整為零,使其易於操作,因為我們要乙個排序的方法。而我們知道,對於點的排序是很容易的。

具體的分治方法是先對其x座標進行排序,再對其進行分治。考慮分治[l,r]為[l,mid]和[mid+1,r],已經分治完了左邊,對於屬於右邊的每乙個要求的點,要把左邊y小於等於它的點全部取計入它的雜湊值(此時左邊經過原來對x的排序已經可以保證x都小於要求的這個點的x了)。

可以證明,迭代log_n次後,所有範圍內的點都可以被計入它的雜湊值(想想為什麼)。

最後比較一下這個點對的雜湊值。

時間複雜度分析

最初的對x排序由於x不超過107

,桶排序可以o(h)過。分治迭代llog_n層,每層詢問要對n個點貢獻雜湊值,每次貢獻需要求y恰好小於等於這個點y值的點,可以用乙個log_n二分找出。

總時間複雜度o(

h+nl

og2n

) 。

問題就完美的解決了。

(最後乙個點奇怪wa掉的**)

#include

#include

#define r register

#define max_rand 1000010

using namespace std;

struct nda[3000010],c[3000010];

struct ansb[500010];

struct ordf[3000010];

int n,m,h,w;

int at=0,ft=0;

int st[10000010];

intread()

bool cmp(const nd &a1,const nd &a2)

if(a[l].y>lim)return

0; return a[r].y

<=lim?r:l;

}void merge_sort(r int l,r int r)

r int i,j,k,mid=(l+r)>>1;

merge_sort(l,mid);

merge_sort(mid+1,r);

for(i=mid+1;i<=r;++i)if(a[i].num!=0)

i=l,j=mid+1,k=l;

while(i<=mid&&j<=r)

while(j<=r)c[k++]=a[j++];

while(i<=mid)c[k++]=a[i++];

a[l]=c[l],a[l].s=(a[l].num==0?a[l].hash:0);

for(i=l+1;i<=r;++i)

a[i]=c[i],a[i].s=a[i-1].s^((a[i].num==0)?a[i].hash:0);

}int main()

; c[++at]=(nd);

b[i].p1=b[i].p2=-1;

}for(i=1;i<=m;++i)

;c[++at]=(nd);

c[++at]=(nd);

c[++at]=(nd);

}for(i=1;i<=at;++i)

f[++ft]=(ord),st[c[i].x]=ft;

for(at=0,i=0;i<=10000002;++i)

for(e=st[i];e!=0;e=f[e].nex)

a[++at]=c[f[e].key];

merge_sort(1,at);

for(i=1;i<=at;++i)

if(a[i].num!=0)

(b[a[i].num].p1==-1)?(b[a[i].num].p1=a[i].hash):(b[a[i].num].p2=a[i].hash);

for(i=1;i<=n;++i)

return

0;}

yzoj P1122 階乘 題解

t組資料,給出n,求出n!最右邊非零的數。對於30 的資料,n 30,t 10。對於全部的資料,n 10 2009,t 30。一道數學題 解析n!10x 最後一位數字即是結果。10x進行拆分,變成5 x 2x。怎麼除以5x呢,好辦,乘的時候含有5的倍數的一項全部不乘進去,再遞迴此過程。即 1 2 3...

YZOJ P1232 異或遊戲

題型特徵 維護區間資訊,需要對每個左端點重新構造情況,不可通過字首和差分。一般方法 對左端點排序,處理每乙個含有這個左端點的區間詢問,並移動左端點。保證了左端點最多經歷le n 次修改。題意描述 t組詢問,每組詢問要求區間 l r 中出現次數為偶數的數的異或和。t 2 105 n 5 105 正解a...

BZOJ3290 花神的數論題

3209 花神的數論題 time limit 10 sec memory limit 128 mb description 背景 眾所周知,花神多年來憑藉無邊的神力狂虐各大 oj oi cf tc 當然也包括 ch 啦。描述 話說花神這天又來講課了。課後照例有超級難的神題啦 我等蒟蒻又遭殃了。花神的...