1. 程式人生 > 其它 >CF1473B String LCM 題解

CF1473B String LCM 題解

CF1473B String LCM 題解

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\)

都能夠被 \(s\) 整除。設我們找出來的這個字串為 \(s_0\),並設 \(s_1\)\(a\)\(s_0\) 拼成,\(s_2\)\(b\)\(s_0\) 拼接而成,那麼只需要連續輸出 \(\operatorname{lcm}(a,b)\)\(s_0\) 就好了。

這種思路說起來容易,程式碼實現卻不是那樣簡單。所以包括巨集定義、標頭檔案和快讀在內,我打了 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;
}