4084 Sdoi2015 雙旋轉字串

2021-07-27 02:27:19 字數 3498 閱讀 4811

time limit: 10 sec  

memory limit: 512 mb

submit: 394  

solved: 161 [

submit][

status][

discuss]

給定兩個字串集合 s 和 t 。其中 s 中的所有字串長度都恰好為 n ,而 t 中所有字串長度都恰好為 m 。且 n+m 恰好為偶數。

如果記 s 中字串全體為 s1,s2,...,stotals ,而 t 中字串全體為 t1,t2,...,ttotalt 。

現在希望知道有多少對 ,滿足將 si 和 tj 拼接後得到的字串 si+tj 滿足雙旋轉性。

乙個長度為偶數字串 w 可以表示成兩段長度相同的字串的拼接,即 w=u+v。如果 v 可以通過 u 旋轉得到,則稱 w 是滿足雙旋轉性的。比如說字串 u=「vijos」可以通過旋轉得到「ijosv」,「josvi」,「osvij」 或「svijo」。那麼「vijosjosvi」就是滿足雙旋轉性的字串。

第一行輸入四個正整數,分別為 totals,totalt,n 和 m,依次表示集合 s 的大小,集合 t 的大小,集合 s 中字串的長度和集合 t 中字串的長度。

之後 totals 行,依次給出 s 中所有的字串 si,1≤i≤totals。保證每乙個字串長度都恰為 n ,且字串只由 26 個小寫字母組成。

之後 totalt 行,依次給出 t 中所有的字串 ti,1≤i≤totalt。保證每乙個字串長度都恰為 m ,且字串只由 26 個小寫字母組成。

1≤n≤100;1≤m≤100;1≤totals≤100;1≤total^t≤100,2≤n*totals+m*totalt≤4×10^6,n>=m

輸出乙個整數,表示滿足要求的數字對 有多少個。

4 4 7 3

vijosvi

josvivi

vijosos

ijosvsv

jos

vij

ijo

jos6 [

submit][

status][

discuss]

一開始題意沒讀好,結果做不出來。。。。

大概是要統計有多少對使得串si + tj左右兩半迴圈同構

不妨假設n >= m,反之情況類似

對於t中的每個字串,先hash一下存在乙個桶裡面

暴力列舉s中的每個字串,假設當前列舉的是si

對於這個串,記mid = (n + m) / 2,si的mid + 1 ~ n位在合併以後顯然是給右邊的半部分用的

可以在1 ~ mid位中暴力查詢一下那些位置往後n - mid位與這個短串相等

每次找到乙個位置,對於1 ~ mid的剩下的字元,後半部在前前半部放後顯然就確定了tj

這時候只要在桶裡面查詢一下這樣的tj有多少就行了

記得統計的時候不能重複,就是一類tj對於每個si只能用一次

用了雙hash + 離散化處理這個桶,,o(|s| * logm),複雜度有點感人。。。

#include#include#include#include#includeusing namespace std;

const int maxn = 4e6 + 4;

const int mod1 = 1000000007;

const int mod2 = 99999983;

typedef long long ll;

struct hash

hash(int h1,int h2): h1(h1),h2(h2){}

hash operator * (const hash &b)

hash operator *= (const hash &b)

hash operator += (const int &b)

hash operator += (const hash &b)

hash operator -= (const hash &b)

bool operator < (const hash &b) const

bool operator == (const hash &b) const

bool operator != (const hash &b) const

}p;

int n,m,ta,tb,mid,cur,cnt;

char ch[maxn];

vector a,b;

vector mi,v,h;

vector cnt,vis;

hash gethash(int l,int r)

void solve1()

sort(v.begin(),v.end()); cnt.push_back(1);

for (int i = 1; i < v.size(); i++)

if (v[i] == v[i - 1]) ++cnt[cur];

else v[++cur] = v[i],cnt.push_back(1);

while (v.size() - 1 > cur) v.pop_back();

for (int i = 0; i <= cur; i++) vis.push_back(0);

for (int i = 0; i < n; i++) h.push_back(hash(0,0));

for (int i = 0; i < ta; i++)

}cout << ans << endl;}

void solve2()

sort(v.begin(),v.end()); cnt.push_back(1);

for (int i = 1; i < v.size(); i++)

if (v[i] == v[i - 1]) ++cnt[cur];

else v[++cur] = v[i],cnt.push_back(1);

while (v.size() - 1 > cur) v.pop_back();

for (int i = 0; i <= cur; i++) vis.push_back(0);

for (int i = 0; i < m; i++) h.push_back(hash(0,0));

for (int i = 0; i < tb; i++)

}cout << ans << endl;}

int main()

for (int i = 0; i < tb; i++)

if (n >= m) solve1(); else solve2();

return 0;

}

4084 Sdoi2015 雙旋轉字串

description 給定兩個字串集合 s 和 t 其中 s 中的所有字串長度都恰好為 n 而 t 中所有字串長度都恰好為 m 且 n m 恰好為偶數。如果記 s 中字串全體為 s1,s2,stotals 而 t 中字串全體為 t1,t2,tt otalt 現在希望知道有多少對 hash 給大的集...

SDOI2015 道路修建

傳送門 線段樹維護最小生成樹。兩個結點合併就是把兩個結點之間的兩條橫邊加上後形成乙個環,然後剪掉環上的最大值即可得到當前最小生成樹。不會證 於是現在只需要考慮怎麼找最大值。首先這個環一定是如下構成 兩邊是左節點的最右豎邊和右節點的最左豎邊,然後中間是所有的上下兩行橫邊。如下圖紅色部分。那麼發現維護每...

SDOI2015 尋寶遊戲

乙個 n n le10 5 個點的帶邊權的樹,初始每個結點都是白色。m m le10 5 次操作,每次將乙個點塗黑 白,問包含所有黑點的最小權連通塊。用set以dfs序為序維護所有黑點,答案即為set內相鄰結點距離和 頭尾結點距離。include include include include in...