首页 > 其他分享 >CodeForces 1286C2 Madhouse (Hard version)

CodeForces 1286C2 Madhouse (Hard version)

时间:2024-02-09 17:33:25浏览次数:24  
标签:typedef frac int Hard CodeForces long version maxn define

洛谷传送门

CF 传送门

可以把限制看成 \(0.75n^2\)。发现 \(0.75n^2 = 0.5n^2 + 2 \times 0.5 (\frac{n}{2})^2\)。这启发我们询问一次 \([1, n]\) 和两次长度为 \(\frac{n}{2}\) 的区间。

不妨问 \([1, n], [1, \frac{n}{2}], [1, \frac{n}{2} + 1]\) 试试。注意到把 \([1, \frac{n}{2} + 1]\) 得到的集合除去 \([1, \frac{n}{2}]\) 中的元素,得到的是左端点在 \([1, \frac{n}{2} + 1]\),右端点为 \(\frac{n}{2} + 1\) 的子串,可以通过这些串中长度为 \(i\) 除去长度为 \(i - 1\) 的串剩下的字符求出原串 \([1, \frac{n}{2} + 1]\) 中的字符。接下来的任务是求 \([\frac{n}{2} + 2, n]\) 中的字符。

考虑 \([1, n]\) 的集合中所有长度为 \(2\) 的串,除了已知的 \(s[1, \frac{n}{2} + 1]\),剩下的只有 \(s_n\) 出现 \(1\) 次,\(s[\frac{n}{2} + 2, n - 1]\) 都是出现 \(2\) 次。那么出现次数为奇数的字母就是 \(s_n\)。

再考虑 \([1, n]\) 中所有长度为 \(3\) 的串。除了已知的 \(s[1, \frac{n}{2} + 1]\) 和 \(s_n\),剩下的只有 \(s_{n - 1}\) 出现 \(2\) 次,\(s[\frac{n}{2} + 2, n - 2]\) 都是出现 \(3\) 次。那么出现次数 \(\bmod\ 3 = 2\) 的字母就是 \(s_n\)。

以此类推,所有长度为 \(i\) 的串中,除去已知的,只有 \(s_{n - i + 2}\) 出现 \(i - 1\) 次,其他未知的都出现 \(i\) 次。所以出现次数 \(\bmod\ i = i - 1\) 的字母就是 \(s_{n - i + 2}\)。这样可以确定 \([\frac{n}{2} + 2, n]\) 的部分。

总共使用 \(3\) 次询问,总子串个数 \(\approx 0.75n^2\)。

code
// Problem: C2. Madhouse (Hard version)
// Contest: Codeforces - Codeforces Round 612 (Div. 1)
// URL: https://codeforces.com/problemset/problem/1286/C2
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 110;

int n, a[26];
string b[maxn];
char ans[maxn];
vector<string> vc[maxn];

inline multiset<string> ask(int l, int r) {
	int n = r - l + 1;
	printf("? %d %d\n", l, r);
	fflush(stdout);
	multiset<string> S;
	for (int _ = 0; _ < n * (n + 1) / 2; ++_) {
		string s;
		cin >> s;
		sort(s.begin(), s.end());
		S.insert(s);
	}
	return S;
}

void solve() {
	scanf("%d", &n);
	if (n <= 3) {
		string ans = "";
		for (int i = 1; i <= n; ++i) {
			ans += *ask(i, i).begin();
		}
		printf("! %s\n", ans.c_str());
		return;
	}
	auto A = ask(1, n), B = ask(1, n / 2), C = ask(1, n / 2 + 1);
	auto D = C;
	for (auto s : B) {
		D.erase(D.find(s));
	}
	int tot = 0;
	for (auto s : D) {
		b[++tot] = s;
	}
	sort(b + 1, b + tot + 1, [&](const string &a, const string &b) {
		return a.size() > b.size();
	});
	ans[tot] = b[tot][0];
	for (int i = tot - 1; i; --i) {
		mems(a, 0);
		for (char c : b[i]) {
			++a[c - 'a'];
		}
		for (char c : b[i + 1]) {
			--a[c - 'a'];
		}
		for (int j = 0; j < 26; ++j) {
			if (a[j]) {
				ans[i] = 'a' + j;
				break;
			}
		}
	}
	for (auto s : C) {
		A.erase(A.find(s));
	}
	for (auto s : A) {
		vc[(int)s.size()].pb(s);
	}
	for (int i = 2; i <= n - n / 2; ++i) {
		mems(a, 0);
		for (auto s : vc[i]) {
			for (char c : s) {
				++a[c - 'a'];
			}
		}
		for (int j = n / 2 + 1, k = i - 1; k; --j, --k) {
			a[ans[j] - 'a'] -= k;
		}
		for (int j = n, k = 1; k <= i - 2; --j, ++k) {
			a[ans[j] - 'a'] -= k;
		}
		for (int j = 0; j < 26; ++j) {
			if (a[j] % i == i - 1) {
				ans[n - i + 2] = 'a' + j;
				break;
			}
		}
	}
	printf("! %s\n", ans + 1);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:typedef,frac,int,Hard,CodeForces,long,version,maxn,define
From: https://www.cnblogs.com/zltzlt-blog/p/18012544

相关文章

  • Educational Codeforces Round 145 (Rated for Div. 2)C. Sum on Subarrays(构造)
    很意思的一道构造题题意:给一个\(n、k\),让构造长度为n的数组满足,子数组为整数的个数为k个,负数的为\(k-(n+1)*n/2\),每个数的范围为\([-1000,1000]\)这种构造题可以考虑就是前一段可以一直用一样的、最小的。我们观察可以发现\(k+k-(n+1)*n/2=(n+1)*n/2\)也就是所有子数组......
  • CodeForces 1927G Paint Charges
    洛谷传送门CF传送门看到\(n\le100\)考虑\(O(\text{poly}(n))\)dp。发现从左向右决策,因为一个点可以向左或向右覆盖,所以需要记最靠左的未覆盖的位置\(j\)和最靠右的已覆盖位置\(k\),状态就是\(f_{i,j,k}\),dp最小的覆盖次数。转移的讨论很简单。考虑不覆盖还是向左......
  • Codeforces Round 919 (Div. 2)
    https://codeforces.com/contest/1920B还行,C、Egood(E据说是很典的dp但我是dp苦手),D、F1无聊,F2不会A.SatisfyingConstraints*800有\(n\)个条件,每个条件形如\(x\gek,x\lek\)或\(x\neqk\),\(k\)为整数。问满足条件的整数\(x\)的个数。先处理\(\ge,\le\),得到限制......
  • Codeforces Round 923 (Div. 3)赛后总结
    CodeforcesRound923(Div.3)A没什么好说的,纯秒。B一开始不知道怎么做,后面用了一个比较麻烦复杂的思路,可以做,但是开数时漏了数组0下标,导致样例一部分一直是空的。C非常简单的一道题,判断条件也比较好找,但是再提醒一遍自己,数组开大点,应该数组开小了,导致样例8没过真的气,最后......
  • Codeforces Round 260 (Div. 1)A. Boredom(dp)
    最开始写了一发贪心wa了,然后这种选和不选的组合优化问题,一般是考虑动态规划\(dp[i][0]:\)表示第i个数不选的最大值\(dp[i][1]:\)表示第i个数选的最大值考虑转移:\(dp[i][0]=max(dp[i-1][1],dp[i-1][0])\)\(dp[i][1]=dp[i-1][1]+a[i]*i\)需要将每一个数用一个桶统计次数因......
  • Codeforces Round 923 (Div. 3)
    A.MakeitWhiteA题不多说B.FollowingtheString题目一开始没看懂,后面发现数字是指字母出现的次数,读懂题目后就好做了,先把26个字母放在一个数组里全部初始化为0,然后用1次就加1,然后要根据数字来选数的话就可以遍历数组当满足就break;也可以通过集合。C.ChoosetheDifferent......
  • Codeforces Round 909 (Div. 3)
    题目链接A.若n是3的倍数,那么输出第二,因为不管先手如何操作,后手只要跟先手出的相反那么先手就永远不会赢其他情况,先手都能赢#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;voidsolve(){intn;cin>>n;if((n+1)%3==0|......
  • Codeforces-Round-917
    比赛链接A.LeastProduct假如序列中有\(0\),那么答案是\(0\)。否则如果有奇数个负数,只需要让每个数的绝对值最大:不操作是最优的。否则如果有偶数个负数,乘积只会\(\ge0\),为了达到最小值\(0\),只需要将任意一个数改成\(0\)。时间复杂度\(\mathcal{O}(n)\)。codeforA......
  • Codeforces-Pinely-Round-3
    比赛链接A.DistinctButtons扣掉一个方向就是只能走到相邻两个象限以及和这两个象限相邻的坐标轴上,判一下是不是所有的点都满足就行。判的时候只需要判是否所有\(x\le0\)(落到二、三象限),或者所有\(x\ge0\)(四、一象限),或者所有\(y\le0\)或者所有\(y\ge0\)就行,......
  • Codeforces Round 923 (Div. 3)
    CodeforcesRound923(Div.3)A-MakeitWhite分析在字符串中找到第一个B的位置l和最后一个B的位置r,打印r-l+1即可如果找不到B打印-1code#include<bits/stdc++.h>#defineintlonglong#defineyescout<<"YES"<<'\n'#defineno cout<<"NO"......