SDOI2010 所駝門王的寶藏

2022-02-04 18:12:02 字數 3851 閱讀 1145

在寬廣的非洲荒漠中,生活著一群勤勞勇敢的羊駝家族。被族人恭稱為「先知」的alpaca l. sotomon是這個家族的領袖,外人也稱其為「所駝門王」。所駝門王畢生致力於維護家族的安定與和諧,他曾親自率軍粉碎河蟹帝國主義的野蠻侵略,為族人立下赫赫戰功。所駝門王一生財寶無數,但因其生性節儉低調,他將財寶埋藏在自己設計的地下宮殿裡,這也是今天henry curtis故事的起點。henry是乙個愛財如命的貪婪傢伙,而又非常聰明,他費盡心機謀劃了這次盜竊行動,破解重重機關後來到這座地下宮殿前。

整座宮殿呈矩陣狀,由r×c間矩形宮室組成,其中有n間宮室裡埋藏著寶藏,稱作藏寶宮室。宮殿裡外、相鄰宮室間都由堅硬的實體牆阻隔,由一間宮室到達另一間只能通過所駝門王獨創的移動方式——傳送門。所駝門王為這n間藏寶宮室每間都架設了一扇傳送門,沒有寶藏的宮室不設傳送門,所有的宮室傳送門分為三種:

「橫天門」:由該門可以傳送到同行的任一宮室;

「縱寰門」:由該門可以傳送到同列的任一宮室;

「九宮門」:由該門可以傳送到以該門所在宮室為中心周圍8格中任一宮室(如果目標宮室存在的話)。

深謀遠慮的henry當然事先就搞到了所駝門王當年的宮殿招標冊,書冊上詳細記錄了每扇傳送門所屬宮室及型別。而且,雖然宮殿內外相隔,但他自行準備了一種可攜式傳送門,可將自己傳送到殿內任意一間宮室開始尋寶,並在任意一間宮室結束後傳送出宮。整座宮殿只許進出一次,且便攜門無法進行宮室之間的傳送。不過好在宮室內傳送門的使用沒有次數限制,每間宮室也可以多次出入。

現在henry已經開啟了便攜門,即將選擇一間宮室進入。為得到盡多寶藏,他希望安排一條路線,使走過的不同藏寶宮室盡可能多。請你告訴henry這條路線最多行經不同藏寶宮室的數目。

以下n行,每行給出一扇傳送門的資訊,包含三個正整數xi, yi, ti,表示該傳送門設在位於第xi行第yi列的藏寶宮室,型別為ti。ti是乙個1~3間的整數,1表示可以傳送到第xi行任意一列的「橫天門」,2表示可以傳送到任意一行第yi列的「縱寰門」,3表示可以傳送到周圍8格宮室的「九宮門」。

保證1≤xi≤r,1≤yi≤c,所有的傳送門位置互不相同。

只有乙個正整數,表示你確定的路線所經過不同藏寶宮室的最大數目。

資料規模和約定:

對於\(100\%\)的資料, \(n\leq 100,000,r\leq 1,000,000,c\leq 1,000,000\)。

一眼 \(tarjan\) 縮點拓撲求最長路。

然而如果直接暴力建邊的話會\(t\)上天,因為這題要建的邊賊多,比如說一行全是橫門,暴力建邊是兩兩之間都建的,最壞複雜度 \(o(n^2)\)。

考慮優化建圖。

觀察到一行的橫門或者一列的縱門一定是在同乙個連通分量裡的,所以我們對於同一行的橫門或者同一行的縱門就沒必要兩兩連邊了,保證直接連成乙個環就好了。

但是如果一行中有很多橫門,同時也有很多其他的門,那麼還是會每個橫門向每個別的種類的門連邊,邊數還是太多。

但是因為一行中的橫門是乙個環,所以對於一行中的其它宮室,只需從環上向這個宮室連一條邊就夠了。

於是得到了下面成型的演算法思路:

我們對於每一行的橫門,每一列的縱門,還有九宮門分開建圖。

第一遍建出橫門向外連的所有邊。第二遍建出縱門向外連的所有邊。第三遍建出九宮門向外連的所有邊。

我們模擬第一次建邊。

因為要優化建邊過程的複雜度,我們想盡可能的先迴圈到橫門,所以可以先排序一遍,這樣的話如果當前不是橫門就可以直接 \(break\) 掉了。

對於所有宮室,我們按照行數排序,保證一行上的所有宮室都會一塊迴圈到。如果行數相同,那麼我們優先將橫門排在前面。

對於迴圈到的每一行的第乙個橫門,我們將其記為 \(first\),同時規定 \(last\) 變數是上乙個掃到的橫門。

然後開始掃這一行的宮室。

如果當前宮室是橫門,那麼 \(add(last,now)\),同時令 \(last=now\)。

否則,\(add(last,now)\)。

最後,\(add(last,first)\)。

這就完成了一行的掃瞄。

縱門也是同理。

對於九宮門,我沒有想出太好的建邊方案,於是直接暴力列舉每個九宮門周圍的八個格仔是否有寶藏。這裡可以用 \(stl\) 的 \(map\) 來儲存每個點是否有寶藏,但是我這裡因為害怕被卡常,手寫了個 \(hash\) 表。

其它就沒什麼了。

我還毒瘤的加上了fread快讀

#include#include#include#include#define n 100005

#define mod 10007

#define ll long long

#define min(a,b) ((a)<(b)?(a):(b))

#define max(a,b) ((a)>(b)?(a):(b))

int x,n,m;

bool in[n];

int cnt,tot,sum;

int head2[n],deg[n];

std::queuetopo;

int stk[n],top,dis[n];

int head[n],belong[n];

int dfn[n],low[n],sze[n];

int hshhead[mod+2],hshcnt;

int dx=;

int dy=;

struct edgeedge[n<<3],edge2[n<<3];

struct hashh[n<<2];

void hshadd(ll x,ll z,int i)

struct nodetype[n];

bool cmp1(node x,node y)

bool cmp2(node x,node y)

void add(int x,int y)

void add2(int x,int y)

inline char nc()

//#define nc getchar

inline int getint()

void tarjan(int now)

else if(in[to])

low[now]=min(low[now],dfn[to]);

}if(low[now]==dfn[now])while(y!=now);

}}void hash()

}int hsh(ll q)

return 0;

}signed main()

hash();

std::sort(type+1,type+1+x,cmp1);

for(int i=1;i<=x;i++)

add(last,type[j].id);

last=type[j].id;

}else add(type[i].id,type[j].id);

}if(last!=fist)

add(last,fist);

i=fina;}}

std::sort(type+1,type+1+x,cmp2);

for(int i=1;i<=x;i++)

add(last,type[j].id);

last=type[j].id;

}else add(type[i].id,type[j].id);

}if(last!=fist)

add(last,fist);

i=fina;}}

for(int i=1;i<=x;i++)

}

for(int i=1;i<=x;i++)

cnt=0;

for(int i=1;i<=x;i++)

}int ans=0;

for(int i=1;i<=tot;i++)

}while(topo.size())

}printf("%d\n",ans);

return 0;

}

SDOI2010 所駝門王的寶藏

題面 題解我寫的是讓同一行 同一列的點形成乙個環,表示它們互相可達。aysn 寫的是對於同一行列建乙個新點表示互相可達。看了窩還是太弱了,還須多練。include include include include include include include include define ri re...

P2403 SDOI2010 所駝門王的寶藏

在寬廣的非洲荒漠中,生活著一群勤勞勇敢的羊駝家族。被族人恭稱為 先知 的alpaca l.sotomon是這個家族的領袖,外人也稱其為 所駝門王 所駝門王畢生致力於維護家族的安定與和諧,他曾親自率軍粉碎河蟹帝國主義的野蠻侵略,為族人立下赫赫戰功。所駝門王一生財寶無數,但因其生性節儉低調,他將財寶埋藏...

bzoj 1924 所駝門王的寶藏

題目大意 有乙個r c的矩陣,上面有n個點有寶藏 每個有寶藏的點上都有傳送門 傳送門有三種 第一種可以傳到該行任意乙個有寶藏的點,第二種可以傳到該列任意乙個有寶藏的點,第三種可以傳到周圍的八連塊上有寶藏的點 現在你可以在任意乙個有寶藏的點開始,求你最多可以經過多少個不同的藏寶點 每個藏寶點可以多次進...