Pagini recente » Cod sursa (job #3335578) | Cod sursa (job #3329060) | Cod sursa (job #3306612) | Cod sursa (job #3308890) | Cod sursa (job #3309051)
/*
https://x.com/tigermcsr/status/1961877831358529714
*/
#include <bits/stdc++.h>
#define MOD 1000000007
#define B 127
using namespace std;
vector<int> powb(30005);
void bing() {
powb[0] = 1;
for(int i = 1; i <= 30000; i ++) {
powb[i] = 1ll * powb[i - 1] * B % MOD;
}
}
void imhashingit(string &s, vector<int> &hash) {
hash.push_back(0);
hash[0] = s[0];
for(int i = 1; i < s.size(); i ++) {
hash.push_back((1ll * hash[i - 1] * B % MOD + s[i]) % MOD);
}
}
int whatsthehash(int st, int dr, vector<int> &hash) {
if(st == 0)
return hash[dr];
st --;
return (hash[dr] - (1ll * hash[st] * powb[dr - st] % MOD) + MOD) % MOD;
}
int findoverlap(vector<int> &hash1, vector<int> &hash2) {
int n = hash1.size();
int m = hash2.size();
int st1 = n - min(n, m), dr1 = n - 1, st2 = 0, dr2 = min(n, m) - 1;
for(; st2 <= dr2; st1 ++, dr2 --) {
if(whatsthehash(st1, dr1, hash1) == whatsthehash(st2, dr2, hash2))
return dr2 + 1;
}
return 0;
}
bool isstringinstring(vector<int> &hash1, vector<int> &hash2) {
int n, m;
n = hash1.size();
m = hash2.size();
if(n > m)
return false;
int st1 = 0, dr1 = n - 1;
int st2 = 0, dr2 = n - 1;
for(; dr2 < m; st2 ++, dr2 ++) {
if(whatsthehash(st1, dr1, hash1) == whatsthehash(st2, dr2, hash2))
return true;
}
return false;
}
int main() {
freopen("adn.in", "r", stdin);
freopen("adn.out", "w", stdout);
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int n; cin >> n;
vector<string> s(n);
vector<vector<int>> hash(n);
vector<vector<int>> overlap(n, vector<int>(n));
bing();
for(int i = 0; i < n; i ++) {
cin >> s[i];
imhashingit(s[i], hash[i]);
}
// cout << whatsthehash(0, s[0].size() - 1, hash[0]);
// cout << whatsthehash(4, 15, hash[4]);
for(int i = 0; i < n; i ++) {
for(int j = 0; j < n; j ++) {
if(i == j)
continue;
if(isstringinstring(hash[i], hash[j])) {
s.erase(s.begin() + i);
hash.erase(hash.begin() + i);
i --;
n --;
break;
}
}
}
for(int i = 0; i < n; i ++) {
for(int j = 0; j < n; j ++) {
if(i == j)
continue;
overlap[i][j] = findoverlap(hash[i], hash[j]);
}
}
// for(int i = 0; i < n; i ++) {
// for(int j = 0; j < n; j ++) {
// cout << overlap[i][j] << ' ';
// }
// cout << '\n';
// }
vector<vector<int>> dp((1 << n), vector<int>(n, 1e9));
// vector<vector<vector<char>>> order((1 << n), vector<vector<char>>(n)); /// MLE on 1 test like fuck u, im gonna end it
vector<vector<int>> last((1 << n), vector<int>(n, -1));
for(int i = 0; i < n; i ++) {
dp[(1 << i)][i] = s[i].size();
// order[(1 << i)][i].push_back(i);
}
for(int mask = 1; mask < (1 << n); mask ++) {
for(int i = 0; i < n; i ++) {
if((mask & (1 << i)) == 0)
continue;
for(int j = 0; j < n; j ++) {
if((mask & (1 << j)) != 0)
continue;
// dp[mask ^ (1 << j)][j] = min(dp[mask ^ (1 << j)][j], dp[mask][i] + (int)s[j].size() - overlap[i][j]);
if(dp[mask ^ (1 << j)][j] > dp[mask][i] + (int)s[j].size() - overlap[i][j]) {
dp[mask ^ (1 << j)][j] = dp[mask][i] + (int)s[j].size() - overlap[i][j];
last[mask ^ (1 << j)][j] = i;
// order[mask ^ (1 << j)][j] = order[mask][i];
// order[mask ^ (1 << j)][j].push_back(j);
}
}
}
}
int ans = 1e9;
vector<char> orderans;
int anspos = -1;
for(int i = 0; i < n; i ++) {
// ans = min(ans, dp[(1 << n) - 1][i]);
if(ans > dp[(1 << n) - 1][i]) {
ans = dp[(1 << n) - 1][i];
// orderans = order[(1 << n) - 1][i];
anspos = i;
}
}
// cout << *(s[0].begin() + 0);
int mask = (1 << n) - 1;
while(anspos>= 0) {
orderans.push_back(anspos);
int nwpos = last[mask][anspos];
mask ^= (1 << anspos);
anspos = nwpos;
}
reverse(orderans.begin(), orderans.end());
cout << s[orderans[0]];
for(int i = 1; i < n; i ++) {
for(int j = overlap[orderans[i - 1]][orderans[i]]; j < s[orderans[i]].size(); j ++) {
cout << s[orderans[i]][j];
}
}
}