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...