Submission #1162602

#TimeUsernameProblemLanguageResultExecution timeMemory
1162602NonozeGenetics (BOI18_genetics)C++20
100 / 100
1601 ms65296 KiB
/*
*	Author: Nonoze
*	Created: Wednesday 05/03/2025
*/
#include <bits/stdc++.h>
using namespace std;
 
namespace std {
 
	// https://judge.yosupo.jp/submission/193613
	struct IOPre {
		static constexpr int TEN = 10, SZ = TEN * TEN * TEN * TEN;
		std::array<char, 4 * SZ> num;
		constexpr IOPre() : num{} {
			for (int i = 0; i < SZ; i++) for (int n = i, j = 3; j >= 0; j--) num[i * 4 + j] = n % TEN + '0', n /= TEN;
		}
	};
	
	struct IO {
	#if !HAVE_DECL_FREAD_UNLOCKED
		#define fread_unlocked fread
	#endif
	#if !HAVE_DECL_FWRITE_UNLOCKED
		#define fwrite_unlocked fwrite
	#endif
		static constexpr int SZ = 1 << 17, LEN = 32, TEN = 10, HUNDRED = TEN * TEN,
							 THOUSAND = HUNDRED * TEN, TENTHOUSAND = THOUSAND * TEN,
							 MAGIC_MULTIPLY = 205, MAGIC_SHIFT = 11, MASK = 15,
							 TWELVE = 12, SIXTEEN = 16;
		static constexpr IOPre io_pre = {};
		std::array<char, SZ> input_buffer, output_buffer;
		int input_ptr_left, input_ptr_right, output_ptr_right;
	
		IO() : input_buffer{}, output_buffer{}, input_ptr_left{}, input_ptr_right{}, output_ptr_right{} {}
		IO(const IO&) = delete;
		IO(IO&&) = delete;
		IO& operator=(const IO&) = delete;
		IO& operator=(IO&&) = delete;
		~IO() { flush(); }
	
		template<typename T> static constexpr bool is_char_v    = std::is_same_v<T, char>;
		template<typename T> static constexpr bool is_bool_v    = std::is_same_v<T, bool>;
		template<typename T> static constexpr bool is_string_v  =
				std::is_same_v<T, std::string> || std::is_same_v<T, const char*> ||
				std::is_same_v<T, char*> || std::is_same_v< std::decay_t<T>, char*>;
		template<typename T> static constexpr bool is_default_v =
				is_char_v<T> || is_bool_v<T> || is_string_v<T> || std::is_integral_v<T>;
	
		inline void load() {
			memmove(std::begin(input_buffer),
					std::begin(input_buffer) + input_ptr_left,
					input_ptr_right - input_ptr_left);
			input_ptr_right =
				input_ptr_right - input_ptr_left +
				fread_unlocked(
					std::begin(input_buffer) + input_ptr_right - input_ptr_left, 1,
					SZ - input_ptr_right + input_ptr_left, stdin);
			input_ptr_left = 0;
		}
	
		inline void read_char(char& c) {
			if (input_ptr_left + LEN > input_ptr_right) load();
			c = input_buffer[input_ptr_left++];
		}
		inline void read_string(std::string& x) {
			char c;
			while (read_char(c), c < '!') continue;
			x = c;
			while (read_char(c), c >= '!') x += c;
		}
		template<typename T>
		inline std::enable_if_t<std::is_integral_v<T>, void> read_int(T& x) {
			if (input_ptr_left + LEN > input_ptr_right) load();
			char c = 0;
			do c = input_buffer[input_ptr_left++];
			while (c < '-');
			[[maybe_unused]] bool minus = false;
			if constexpr (std::is_signed<T>::value == true)
				if (c == '-') minus = true, c = input_buffer[input_ptr_left++];
			x = 0;
			while (c >= '0')
				x = x * TEN + (c & MASK), c = input_buffer[input_ptr_left++];
			if constexpr (std::is_signed<T>::value == true)
				if (minus) x = -x;
		}
	
		inline void skip_space() {
			if (input_ptr_left + LEN > input_ptr_right) load();
			while (input_buffer[input_ptr_left] <= ' ') input_ptr_left++;
		}
	
		inline void flush() {
			fwrite_unlocked(std::begin(output_buffer), 1, output_ptr_right, stdout);
			output_ptr_right = 0;
		}
	
		inline void write_char(char c) {
			if (output_ptr_right > SZ - LEN) flush();
			output_buffer[output_ptr_right++] = c;
		}
	
		inline void write_bool(bool b) {
			if (output_ptr_right > SZ - LEN) flush();
			output_buffer[output_ptr_right++] = b ? '1' : '0';
		}
	
		inline void write_string(const std::string& s) {
			for (auto x : s) write_char(x);
		}
	
		inline void write_string(const char* s) {
			while (*s) write_char(*s++);
		}
	
		inline void write_string(char* s) {
			while (*s) write_char(*s++);
		}
	
		template <typename T>
		inline std::enable_if_t< std::is_integral_v<T>, void> write_int(T x) {
			if (output_ptr_right > SZ - LEN) flush();
			if (!x) {
				output_buffer[output_ptr_right++] = '0';
				return;
			}
			if constexpr (std::is_signed_v<T>) if (x < 0) output_buffer[output_ptr_right++] = '-', x = -x;
			int i = TWELVE;
			std::array<char, SIXTEEN> buf{};
			for (; x >= TENTHOUSAND; x /= TENTHOUSAND, i -= 4)
				memcpy(std::begin(buf) + i, std::begin(io_pre.num) + (x % TENTHOUSAND) * 4, 4);
			if (x < HUNDRED) {
				if (x < TEN) output_buffer[output_ptr_right++] = '0' + x;
				else {
					uint32_t q = (uint32_t(x) * MAGIC_MULTIPLY) >> MAGIC_SHIFT;
					uint32_t r = uint32_t(x) - q * TEN;
					output_buffer[output_ptr_right++] = '0' + q;
					output_buffer[output_ptr_right++] = '0' + r;
				}
			} else {
				if (x < THOUSAND) 
					memcpy(std::begin(output_buffer) + output_ptr_right, std::begin(io_pre.num) + (x << 2) + 1, 3),
					output_ptr_right += 3;
				else
					memcpy(std::begin(output_buffer) + output_ptr_right, std::begin(io_pre.num) + (x << 2), 4),
					output_ptr_right += 4;
			}
			memcpy(std::begin(output_buffer) + output_ptr_right, std::begin(buf) + i + 4, TWELVE - i);
			output_ptr_right += TWELVE - i;
		}
	
		template <typename T_>
		std::enable_if_t<(is_default_v< std::remove_cv_t< std::remove_reference_t<T_> > >), IO&> operator<<(T_&& x) {
			using T = std::remove_cv_t< std::remove_reference_t<T_> >;
			if constexpr (is_bool_v<T>) write_bool(x);
			else if constexpr (is_string_v<T>) write_string(x);
			else if constexpr (is_char_v<T>) write_char(x);
			else if constexpr (std::is_integral_v<T>) write_int(x);
			return *this;
		}
	
		template<typename T>
		std::enable_if_t<(is_default_v<T> && !is_bool_v<T>), IO&> operator>>(T& x) {
			if constexpr (is_string_v<T>) read_string(x);
			else if constexpr (is_char_v<T>) read_char(x);
			else if constexpr (std::is_integral_v<T>) read_int(x);
			return *this;
		}
	
		IO* tie(std::nullptr_t) { return this; }
		void sync_with_stdio(bool) {}
	} io;
	
} // namespace std
 
using std::io;
 
#define cin io
#define cout io
 
#ifndef IN_LOCAL
	#define dbg(...)
#endif
 
// #define cout cerr << "OUT: "
#define endl '\n'
#define endlfl '\n' << flush
#define quit(x) return (void)(cout << x << endl)
 
template<typename T> void read(T& x) { cin >> x;}
template<typename T1, typename T2> void read(pair<T1, T2>& p) { read(p.first), read(p.second);}
template<typename T> void read(vector<T>& v) { for (auto& x : v) read(x); }
template<typename T1, typename T2> void read(T1& x, T2& y) { read(x), read(y); }
template<typename T1, typename T2, typename T3> void read(T1& x, T2& y, T3& z) { read(x), read(y), read(z); }
template<typename T1, typename T2, typename T3, typename T4> void read(T1& x, T2& y, T3& z, T4& zz) { read(x), read(y), read(z), read(zz); }
template<typename T> void print(vector<T>& v) { for (auto& x : v) cout << x << ' '; cout << endl; }
 
#define sz(x) (int)(x.size())
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define make_unique(v) sort(all(v)), v.erase(unique(all(v)), (v).end())
#define pb push_back
#define mp(a, b) make_pair(a, b)
#define fi first
#define se second
#define cmin(a, b) a = min(a, b)
#define cmax(a, b) a = max(a, b)
#define YES cout << "YES" << endl
#define NO cout << "NO" << endl
#define QYES quit("YES")
#define QNO quit("NO")
 
#define int long long
#define double long double
const int inf = numeric_limits<int>::max() / 4;
mt19937 rng(123);
const int MOD = 1e9+7, LOG=20;
 
 
 
void solve();
 
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	int tt=1;
	// cin >> tt;
	while(tt--) solve();
	return 0;
}
 
 
 
 
int n, k, m, q;
vector<string> a;
 
bool ok(int i, int j) {
	if (i==j) return 1;
	int cnt=0;
	for (int l=0; l<m&&cnt<=k&&cnt+(m-l)>=k; l++) cnt+=(a[i][l]!=a[j][l]);
	return cnt==k;
}
 
 
void solve() {
	read(n, m, k);
	a.clear(), a.resize(n); read(a);
 
	map<string, int> nb;
	for (auto u: a) nb[u]++;
 
	vector<pair<string, int>> b;
	for (int i=0; i<n; i++) if (nb[a[i]]==1) b.pb({a[i], i}), nb[a[i]]*=-1;
	shuffle(all(b), rng);
	n=sz(b);
	a.clear(), a.resize(n);
	for (int i=0; i<n; i++) a[i]=b[i].fi;
	dbg(a);
 
	vector<vector<int>> freq(m, vector<int>(4));
	for (int i=0; i<n; i++) for (int j=0; j<m; j++) {
		if (a[i][j]=='A') freq[j][0]++;
		if (a[i][j]=='C') freq[j][1]++;
		if (a[i][j]=='T') freq[j][2]++;
		if (a[i][j]=='G') freq[j][3]++;
	}
 
	vector<bool> imposs(n);
	vector<int> OK;
 
	for (int i=0; i<n; i++) {
		int nbdiff=0;
		for (int j=0; j<m; j++) {
			nbdiff+=n;
			if (a[i][j]=='A') nbdiff-=freq[j][0];
			if (a[i][j]=='C') nbdiff-=freq[j][1];
			if (a[i][j]=='T') nbdiff-=freq[j][2];
			if (a[i][j]=='G') nbdiff-=freq[j][3];
		}
		if (nbdiff==k*(n-1)) {
			OK.pb(i);
		} else imposs[i]=1;
	}
	freq.clear(); freq.resize(m, vector<int>(4));
	for (int i=0; i<sz(OK); i++) for (int j=0; j<m; j++) {
		if (a[OK[i]][j]=='A') freq[j][0]++;
		if (a[OK[i]][j]=='C') freq[j][1]++;
		if (a[OK[i]][j]=='T') freq[j][2]++;
		if (a[OK[i]][j]=='G') freq[j][3]++;
	}
	for (int i=0; i<sz(OK); i++) {
		int nbdiff=0;
		for (int j=0; j<m; j++) {
			nbdiff+=sz(OK);
			if (a[OK[i]][j]=='A') nbdiff-=freq[j][0];
			if (a[OK[i]][j]=='C') nbdiff-=freq[j][1];
			if (a[OK[i]][j]=='T') nbdiff-=freq[j][2];
			if (a[OK[i]][j]=='G') nbdiff-=freq[j][3];
		}
		if (nbdiff!=k*(sz(OK)-1)) imposs[i]=1;
	}
	// cerr << sz(OK) << endl;
 
	queue<int> pos;
	int comp=0;
	for (int i=0; i<1000*n; i++) {
		comp++;
		bool impossible=0;
		while (!pos.empty()) {
			if (ok(pos.front(), i%n)) break;
			pos.pop(), impossible=1;
			comp=0;
		}
		if (i<n && !impossible && !imposs[i] && nb[a[i]]==-1) pos.push(i);
		if (i>=n-1 && sz(pos)==1) break;
		if (comp>n) break;
	}
	quit(b[pos.front()].se+1);
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...