Cod sursa(job #3255943)

Utilizator Dani111Gheorghe Daniel Dani111 Data 12 noiembrie 2024 19:43:27
Problema ADN Scor 80
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.6 kb
#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;
}