解:sam + 線段樹合併 + dfs序。
姓和名之間插入特殊字元,轉化為下題:
給定串集合s,t,問s中每個串包含了t中的幾個串?t中每個串被多少個s中的串包含?
解:對s建廣義sam,並線段樹合併維護每個節點有多少串。
t中每個串在s的sam上跑,如果沒能跑完就被包含0次。否則答案就是到達的節點上的串數。第二問解決。
標記t中每個串最後到達的節點。s中每個串跑s的sam會得到若干個點。統計這些點到根路徑的並集上的標記個數即可。
按dfs序排序,加上每個節點到根路徑的貢獻,減去相鄰節點lca到根路徑的貢獻。第一問解決。
1 #include 2ac**3const
int n = 400010, m = 10000010;4
5struct
edge edge[n]; int
tp;8
9 std::maptr[n];
10int fail[n], len[n], tot = 1
, e[n], n, m, siz[n], ed[n],
11 stk[n], top, num2, pos2[n], st[n << 1][22], pw[n << 1
], d[n];
12int
ls[m], rs[m], num, sum[m], rt[n];
13 std::vectorstr[n];
1415 inline void add(int x, int
y) 22
23 inline bool cmp(const
int &a, const
int &b)
2627
void insert(int p, int l, int r, int &o)
33int mid = (l + r) >> 1;34
if(p <=mid) insert(p, l, mid, ls[o]);
35else insert(p, mid + 1
, r, rs[o]);
36 sum[o] = sum[ls[o]] +sum[rs[o]];
37return;38
}3940int merge(int x, int
y) 49
50int ask(int l, int r, int l, int r, int
o) 58
59void dfs_1(int
x) 69
return;70
}7172 inline void
prework() 81}
82return;83
}8485 inline int lca(int x, int
y) 95
96void dfs_2(int
x) 103
return
;104
}105
106 inline int split(int p, int
f) 117
return
nq;118
}119
120 inline int insert(int p, int f, int
id)
127else
130 insert(id, 1
, n, rt[np]);
131return
np;132
}133 np = ++tot;
134 len[np] = len[p] + 1
;135
while(p && !tr[p].count(f))
139if(!p)
142else
147else
150}
151 insert(id, 1
, n, rt[np]);
152return
np;153
}154
155void
out(int l, int r, int
o) 161
int mid = (l + r) >> 1
;162
out(l, mid, ls[o]);
163out(mid + 1
, r, rs[o]);
164return
;165
}166
167 inline void
clear()
172for(int i = 1; i <= num; i++)
175 tp = num = 0
;176 tot = 1
;177
return
;178
}179
180int
main()
190 str[i].push_back(-1
);191 p = insert(p, -1
, i);
192 scanf("
%d", &k);
193for(int j = 1; j <= k; j++)
198}
199///
build
200for(int i = 2; i <= tot; i++)
204 dfs_1(1
);205
206for(int i = 1; i <= m; i++)
214if(!fd)
218 printf("
%d\n
", ans);
219}
220221 dfs_2(1
);222
prework();
223224
for(int i = 1; i <= n; i++)
231 std::sort(stk + 1, stk + top + 1
,cmp);
232 top = std::unique(stk + 1, stk + top + 1) - stk - 1
;233
int ans = 0
;234
for(int j = 1; j <= top; j++)
238 printf("
%d "
, ans);
239}
240241
return0;
242 }
ac自動機解法。
喵星球上的點名
a180285幸運地被選做了地球到喵星球的留學生。他發現喵星人在上課前的點名現象非常有趣。假設課堂上有n個喵星人,每個喵星人的名字由姓和名構成。喵星球上的老師會選擇m個串來點名,每次讀出乙個串的時候,如果這個串是乙個喵星人的姓或名的子串,那麼這個喵星人就必須答到。然而,由於喵星人的字碼過於古怪,以至...
SCOI2012 喵星球上的點名
有n個串,代表n個人的姓氏和名字,都是用很多個數字表示的,比如我姓1,2,3,4,名4,5,6,7。然後有m個點名串,如果點到了某個人的姓或名裡面的某一串,那個人就被點到,不過乙個人在乙個點名串中只能被點一次。比如點名串是2,3,4,我的姓中含有2,3,4,那麼我就會被叫到。求每個學生分別被叫到多少...
SCOI2012 喵星球上的點名
給出n個模式串,m個文字串,每個模式串由兩部分組成,我們認為乙個模式串被乙個文字串包含只要這個文字串包含它的兩部分中的其中一部分的子串。求每個文字串包含多少個模式串,每個模式串又被多少個文字串包含。1 n 20000,1 m 50000,模式串總長和文字串的總長分別不超過100000 保證模式串和文...