CF1473B String LCM 題解
阿新 • • 發佈:2021-12-16
CF1473B String LCM 題解
都能夠被 \(s\) 整除。設我們找出來的這個字串為 \(s_0\),並設 \(s_1\) 由 \(a\) 個 \(s_0\) 拼成,\(s_2\) 由 \(b\) 個 \(s_0\) 拼接而成,那麼只需要連續輸出 \(\operatorname{lcm}(a,b)\) 個 \(s_0\) 就好了。
Content
如果一個字串 \(s\) 由若干個字串 \(t\) 拼接而成,則我們說 \(s\) 能被 \(t\) 整除。定義 \(s_1,s_2\) 的最短公倍串為可以同時被 \(s_1,s_2\) 的最短非空字串。給定 \(T\) 對字串 \(s_1,s_2\),求出每對字串的最短公倍串。
資料範圍:\(T\in[1,2000],|s_1|,|s_2|\in[1,20]\)。
Solution
《記我用 1.81k 程式碼過了一道普及- 的題目》
由於資料範圍小得可憐,我們可以先暴力求出 \(s_1,s_2\) 的所有非空子串,然後再判斷兩個字串是否同時存在一個子串 \(s\),使得 \(s_1,s_2\)
這種思路說起來容易,程式碼實現卻不是那樣簡單。所以包括巨集定義、標頭檔案和快讀在內,我打了 1.81k 的程式碼。
你可以去這裡看到我和其他一些神仙的程式碼長度比較,由此可以看出我很菜qwq。
Code
string s1, s2, subs1[27], subs2[27], pos[27], ans; int t, pos1[27], pos2[27], poscnt; map<string, int> vis; inline int gcd(int a, int b) {return !b ? a : gcd(b, a % b);} inline int lcm(int a, int b) {return a * b / gcd(a, b);} int main() { //freopen(".in", "r", stdin); //freopen(".out", "w", stdout); t = Rint; while(t--) { F(i, 1, 20) subs1[i] = ""; F(i, 1, 20) subs2[i] = ""; F(i, 1, 20) pos[i] = ""; memset(pos1, 0, sizeof(pos1)), memset(pos2, 0, sizeof(pos2)); vis.clear(); poscnt = 0; ans = ""; cin >> s1 >> s2; int len1 = s1.size(), len2 = s2.size(); F(i, 1, len1) subs1[i] = s1.substr(0, i); F(i, 1, len2) subs2[i] = s2.substr(0, i); F(i, 1, len1) { if(len1 % i) continue; string s = ""; F(j, 1, len1 / i) s += subs1[i]; if(s == s1) pos1[++pos1[0]] = len1 / i, pos[++poscnt] = subs1[i], vis[subs1[i]] = pos1[0]; } F(i, 1, len2) { if(len2 % i) continue; string s = ""; F(j, 1, len2 / i) s += subs2[i]; if(s == s2 && vis[subs2[i]]) pos2[++pos2[0]] = len2 / i, ans = subs2[i]; } if(ans == "") {puts("-1"); continue;} F(i, 1, lcm(pos1[vis[ans]], pos2[pos2[0]])) cout << ans; puts(""); } return 0; }