B 数一数 kmp 字符串匹配数量之积
链接:https://ac.nowcoder.com/acm/contest/27589/B
来源:牛客网
题目描述
设 s,ts,ts,t 为两个字符串,定义 f(s,t)=tf(s,t) = tf(s,t)=t 的子串中,与 sss 相等的串的个数。如 f("ac","acacac")=3f("ac","acacac")=3f("ac","acacac")=3 , f("bab","babab")=2f("bab","babab")=2f("bab","babab")=2。
现在给出 nnn 个字符串,第 iii 个字符串为 sis_isi。你需要对∀1≤i≤n\forall 1 \leq i \leq n∀1≤i≤n,求出∏j=1nf(si,sj)\prod_{j=1}^n {f(s_i,s_j)}∏j=1nf(si,sj)。
由于答案很大,你只需要输出对 998244353 取模后的结果。
输入描述:
第一行一个整数 nnn。
接下来 nnn 行每行一个仅由英文字母构成的非空字符串,第 iii 个字符串代表 sis_isi。
输出描述:
共 nnn 行,第 iii 行输出对 998244353 取模的结果。
备注:
1≤n≤1061 ≤ n ≤ 10^61≤n≤106,所有字符串的总长度不超过 2×1062 \times10^62×106
分析:
由于长度长的字符串不可能是长度短的字符串的子串
所以只要找出长度最短的字符串,用它们来匹配其它所有字符串就可以了
//-------------------------代码---------------------------- #define int ll const int N = 3e6+10; int n,m; string s[N]; int nxt[N]; void solve() { // cin>>n>>m; cin>>n; int mn = 1e18; fo(i,1,n) { cin>>s[i]; mn = min((int)s[i].size(),mn); } bool f = 1; bool first = 0; string tmp; set<int> q; fo(i,1,n) { if(s[i].size() == mn) { if(first == 0) { tmp = s[i]; } else { if(tmp != s[i]) { f = 0; break; } } q.insert(i); } } if(!f) { fo(i,1,n) cout<<0<<'\n'; return; } tmp = ' ' + tmp; fo(i,2,mn) { nxt[i] = nxt[i-1]; while(nxt[i] && tmp[nxt[i] + 1] != tmp[i]) nxt[i] = nxt[nxt[i]]; if(tmp[nxt[i] + 1] == tmp[i]) nxt[i] ++ ; } fo(i,1,mn) { // cout<<nxt[i]<<' '<<i<<endl; } ll ans = 1; fo(k,1,n) { if(q.count(k)) continue; int j = 1; string ss = s[k]; int lens = ss.size(); ss = ' ' + ss; ll d = 0; fo(i,1,lens) { while(j!=1 && ss[i] != tmp[j]) j = nxt[j-1] + 1; if(tmp[j] == ss[i]) j ++ ; if(j == mn + 1) { d ++ ; j = nxt[j-1] + 1; } } ans *= d; ans %= 998244353; } fo(i,1,n) { if(q.count(i)) { cout<<ans<<'\n'; } else cout<<0<<'\n'; } } void main_init() {} signed main(){ AC();clapping();TLE; cout<<fixed<<setprecision(12); main_init(); // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------