Pagini recente » preONI 2008, Runda Finala, Clasele 5-8 | Cod sursa (job #1091714) | Monitorul de evaluare | Cod sursa (job #153967) | Cod sursa (job #3255943)
#include <bits/stdc++.h>
using namespace std;
const int MAX1 = 3 * 1e4;
const int MAXN = 18;
const int MOD = 1e9 + 7;
int cost[MAXN + 3][MAXN + 3];
int N;
int N1;
bool subsec[MAXN + 3];
int dp[(1 << 18) + 3][18];
vector<char>ans;
string s[MAXN + 3];
string s1[MAXN + 3];
int pw28[MAX1 + 3];
int pw(int A, int N) {
if(N == 0) return 1;
if(N % 2 == 1) {
return (1LL * A * pw(A, N - 1)) % MOD;
}
int P = pw(A, N / 2) % MOD;
return (1LL * P * P) % MOD;
}
int main() {
freopen("adn.in", "r", stdin);
freopen("adn.out", "w", stdout);
cin.tie(0);
cout.tie(0);
ios_base::sync_with_stdio(false);
cin >> N;
for(int i = 1; i <= N; i++) {
cin >> s[i];
}
pw28[0] = 1;
for(int i = 1; i <= MAX1; i++) {
pw28[i] = (1LL * pw28[i - 1] * 28) % MOD;
}
//verific daca sirul i e subsir al unui alt sir, caz in care nu mai
//trebuie inclus
for(int i = 1; i <= N; i++) {
int hash1 = 0;
for(int j = 0; j < s[i].size(); j++) {
hash1 = (1LL * hash1 * 28 + (s[i][j] - 'A' + 1)) % MOD;
}
for(int j = 1; j <= N; j++) {
if(s[j].size() > s[i].size()) {
int hash2 = 0;
for(int l = 0; l < s[j].size(); l++) {
hash2 = (1LL * hash2 * 28 + (s[j][l] - 'A' + 1)) % MOD;
//cout << l - (int)s[i].size() << ' ';
if(l - (int)s[i].size() >= 0)
hash2 -= (1LL * (s[j][l - (int)s[i].size()] - 'A' + 1) * pw28[s[i].size()]) % MOD;
hash2 = (hash2 + MOD) % MOD;
if(hash1 == hash2) {
//cout << i << ' ' << j << '\n';
subsec[i] = 1;
}
// if(j == 5 && i == 1) {
// cout << hash1 << ' ' << hash2 << '\n';
// }
//cout << hash1 << ' ' << hash2 << '\n';
}
}
}
}
for(int i = 1; i <= N; i++) {
for(int j = i + 1; j <= N; j++) {
if(s[i] == s[j]) subsec[i] = 1;
}
}
for(int i = 1; i <= N; i++) {
if(subsec[i] != 1) {
s1[N1] = s[i];
s[i].clear();
N1++;
}
}
//costul sa il adaug pe j dupa i
for(int i = 0; i < N1; i++) {
for(int j = 0; j < N1; j++) {
if(i == j) continue;
int j1 = s1[i].size() - 1;
int j2 = 0;
int hash1 = 0, hash2 = 0;
cost[i][j] = s1[j].size();
while(j1 >= 0 && j2 < s1[j].size()) {
hash1 = (hash1 + 1LL * (s1[i][j1] - 'A' + 1) * (pw28[s1[i].size() - j1 - 1])) % MOD;
hash2 = (1LL * hash2 * 28 + (s1[j][j2] - 'A' + 1)) % MOD;
if(hash1 == hash2) {
cost[i][j] = s1[j].size() - j2 - 1;
}
j1--; j2++;
}
}
}
// for(int i = 1; i <= N1; i++) {
// for(int j = 1; j <= N1; j++) {
// cout << cost[i][j] << ' ';
// }
// cout << '\n';
// }
/*
dp[mask][i] = costul minim pentru un sir care contine elementele din mask
si are ca ultim sir pe i
*/
for(int mask = 0; mask < (1 << (N1)); mask++) {
for(int i = 0; i < N1; i++) {
dp[mask][i] = INT_MAX / 2;
}
}
for(int i = 0; i < N1; i++) {
dp[(1 << i)][i] = s1[i].size();
}
//cout << N1 << '\n';
for(int mask = 0; mask < (1 << (N1)); mask++) {
for(int j = 0; j < N1; j++) {
for(int l = 0; l < N1; l++) {
if(j == l) continue;
if((mask & (1 << j)) && (mask & (1 << l))) {
dp[mask][j] = min(dp[mask][j], dp[mask - (1 << j)][l] + cost[l][j]);
//cout << dp[mask][j] << '\n';
//cout << (mask - (1 << j)) << ' ' << l << ' ' << dp[3][1] << '\n';
}
}
}
}
// for(int mask = 0; mask < (1 << N1); mask++) {
// for(int i = 1; i <= N1; i++) {
// cout << dp[mask][i] << ' ';
// }
// cout << '\n';
// }
//cout << cost[1][0] << '\n';
// for(int i = 0; i < N1; i++) {
// for(int j = 0; j < N1; j++) {
// cout << cost[i][j] << ' ';
// }
// cout << '\n';
// }
int minn = INT_MAX / 2, pozmin = 0;
for(int i = 0; i < N1; i++) {
if(minn > dp[(1 << N1) - 1][i]) {
minn = dp[(1 << N1) - 1][i];
pozmin = i;
}
}
int mask = ((1 << N1) - 1);
int cnt = 0;
while(mask) {
for(int i = 0; i < N1; i++) {
if(dp[mask - (1 << pozmin)][i] == dp[mask][pozmin] - cost[i][pozmin]) {
mask -= (1 << pozmin);
for(int j = s1[pozmin].size() - 1; j >= s1[pozmin].size() - 1 - cost[i][pozmin] + 1; j--) {
ans.push_back(s1[pozmin][j]);
}
pozmin = i;
//cout << mask << ' ';
break;
}
}
int cnt = 0;
for(int i = 0; i < N1; i++) {
if(mask & (1 << i)) cnt++;
}
if(cnt == 1) {
for(int i = 0; i < N1; i++) {
if(mask & (1 << i)) {
for(int j = s1[i].size() - 1; j >= 0; j--) {
ans.push_back(s1[i][j]);
}
mask -= (1 << i);
}
}
}
}
reverse(ans.begin(), ans.end());
for(auto i : ans) cout << i;
}