SDOI2008 Sandy的卡片(字尾陣列)

2022-07-24 12:00:13 字數 2922 閱讀 8916

sandy和sue的熱衷於收集乾脆麵中的卡片。

然而,sue收集卡片是因為卡片上漂亮的人物形象,而sandy則是為了積攢卡片兌換超炫的人物模型。

每一張卡片都由一些數字進行標記,第i張卡片的序列長度為mi,要想兌換人物模型,首先必須要集夠n張卡片,對於這n張卡片,如果他們都有乙個相同的子串長度為k,則可以兌換乙個等級為k的人物模型。相同的定義為:兩個子串長度相同且乙個串的全部元素加上乙個數就會變成另乙個串。

sandy的卡片數遠遠小於要求的n,於是sue決定在sandy的生日將自己的卡片送給sandy,在sue的幫助下,sandy終於集夠了n張卡片,但是,sandy並不清楚他可以兌換到哪個等級的人物模型,現在,請你幫助sandy和sue,看看他們最高能夠得到哪個等級的人物模型。

第一行為乙個數n,表示可以兌換人物模型最少需要的卡片數,即sandy現在有的卡片數

第i+1行到第i+n行每行第乙個數為第i張卡片序列的長度mi,之後j+1到j+1+mi個數,用空格分隔,分別表示序列中的第j個數

乙個數k,表示可以獲得的最高等級。

輸入 #1

2

2 1 2

3 4 5 9

輸出 #1

2資料範圍:

30%的資料保證n<=50

100%的資料保證n<=1000,m<=1000,2<=mi<=101

update:題面上資料範圍mi和m的範圍其實是乙個東西... 真實資料範圍:40<=n<=1000,2<=mi<=101,字串中的每個數字的大小範圍為[0,1864]

【題目大意】

給定 n 個序列,求 n 個序列中相同的子串的最大長度,相同的定義是給每個子串裡面的每個數加上乙個數等於另外乙個序列

【思路描述】

首先是想到將問題轉化為字尾陣列進行乙個字串的操作

我們可以想到,當前後兩數之差和另外乙個序列中的另外相鄰兩數之差相等時

給前者兩個數加乙個相同的數就能夠得到另外乙個序列

所以問題就能夠轉化為連續相鄰兩數之差相同的最長子串長度

子串,相同,數字一定屬於一定範圍而且比較小,好,字尾陣列能寫

把所有序列拼成乙個序列,做成乙個字串

每個序列中間用乙個不同大數隔開

然後怎麼查詢這個長度呢

二分這個長度

然後考慮 check 函式怎麼寫

比較 height [ i ] 當 i 的height [ i ] 大於長度的時候,說明這個序列符合要求

因為是按照字典序在檢索,所以能夠不錯漏,

其實有點像是在找 height 的最小值,同時保證每個最小值在不同的序列中

當找到 n 個的時候說明每個序列都有大於等於這個長度的相同子串

沒有找到的時候說明沒有,

然後二分

最後輸出答案,因為我們判斷的是差,而第乙個字元沒有被判定

所以答案 + 1

【**】

注意:

1 . 因為是按照數字的大小排序,所以注意處理差的正負,把所有的負差需要變成正的

同時加乙個數不破壞這個序列的屬性,直接加最小值即可

2 . 因為有可能前後兩個數字相同,於是差是0,為了和開頭的0避開,給 0+1

#include#include

#include

#include

using

namespace

std;

const

int max = 1010

;const

int maxm = 6010

;const

int maxn = max * (maxm + 1

);const

int dot = 2000

;int down = 2000

;int n = 0,num,m=-1

;int

a[max][maxm], len[maxm],b[maxn];

intsa[maxn], height[maxn];

intrak[maxn],id[maxn];

intc[maxn], x[maxn], y[maxn];

bool

vis[maxn];

void get_sa(int *s)

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

rak[sa[i]] =i;

return;}

void get_height(int *s)

}int

sta[maxn];

int top = 0

;bool check(int

x)

if (!vis[id[sa[i]]])

}return0;

}int

main()

}n = 0

;

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

b[++n] = ++down;

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

get_sa(b);

//printf("**\n");

get_height(b);

//printf("**\n");

int ans=0

;

int l = 1

;

while (l <=r)

else

}//printf("**\n");

printf("

%d", ans+1

);

return0;

}

view code

SDOI2008 燒水問題

把總質量為1kg的水分裝在n個杯子裡,每杯水的質量均為 1 n kg,初始溫度均為0 現需要把每一杯水都燒開。我們可以對任意一杯水進行加熱。把一杯水的溫度公升高t 所需的能量為 4200 t n j,其中,j 是能量單位 焦耳 如果一旦某杯水的溫度達到100 那麼這杯水的溫度就不能再繼續公升高,此時...

SDOI2008 洞穴勘測

lct維護連通性型別的題目,主要是要搞清楚findroot函式的作用 判斷根是否相同,和並查集裡面的find 函式有異曲同工之妙,如果根相同可以認為兩個點具有連通性。先access打通一道到x的實邊,現在x是深度最大的節點。然後再splay x到根節點,因為它深度最大,這個時候它只有左子樹。所以找它...

SDOI2008 燒水問題

把總質量為1kg的水分裝在n個杯子裡,每杯水的質量均為 1 n kg,初始溫度均為0 現需要把每一杯水都燒開。我們可以對任意一杯水進行加熱。把一杯水的溫度公升高t 所需的能量為 4200 t n j,其中,j 是能量單位 焦耳 如果一旦某杯水的溫度達到100 那麼這杯水的溫度就不能再繼續公升高,此時...