C题意:
[1 n] 的排列,我们要任意相邻的数相加得到的和是合数。
如果对于n 不存在这个一个排列,那么输出-1
一个比较显然的思路
就是奇数放一起,偶数放一起。奇数之间相加是偶数
偶数之间相加是偶数。那么他们都是合数。
但是还有 奇偶相邻的地方,会出现一个奇数+偶数的情况。
我们应该怎么安排这个位置上的数字?
考虑一些特定的元素,
5 +4 =9
再小的 奇数+偶数不会出现合数了。
所以对于n <=4 的情况,直接输出-1 了。
当n >4 的时候,直接将奇偶相接的地方规定为 5 4 就可以了
E题意:
长度为n 的二进制串,可以询问 l r 之内的01 的子序列个数。
至多询问n 次,确定这个字符串或者判定没有这样的字符串
其实一直很不会做这种有点构造感觉的题。呃呃,还是得多练
先来思考在 一段知道01 子序列个数的段之后,我们在多询问一位,如果变多了那么这一位 是1,如果没有变那么这一位只能是0。
因为只能询问n次,我们询问(0 1)(0 2)…(0 n-1)这些前缀。确定每一位上的数字。
最后我们将我们生成的01串,在和每个前缀的01 序列作比较。因为我们之前只是将增多变成这一位是1,但是可能增加的数量不对。
我第一个不是零的下标。如果是 i ,那么前面有 (i-t)个1,有t 个0.
丑陋的代码~~
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int ask(int x, int y)
{cout << "? " << x + 1 << " " << y + 1 << endl;int ans;cin >> ans;return ans;
}
void solve()
{int n;cin >> n;string s = " ";vector<int> a(n);int la = 0;bool f = 0;for (int i = 1; i < n; i++){int t = ask(0, i);a[i] = t;if (t == la)s += '0';else{if (!f){if (t == i)s[0] = '0';else{int t1 = i - t;int t2 = t;s.clear();for (int i = 0; i < t1; i++)s += '1';for (int i = 0; i < t2; i++)s += '0';}}s += '1';la = t;f = 1;}}bool f1 = 0;for (int i = 0; i < n; i++)if (a[i] != 0){f1 = 1;}if (!f1){cout << "! IMPOSSIBLE" << endl;return;}int cnt0 = 0;int ans = 0;for (int i = 0; i < n; i++){if (s[i] == '0')cnt0++;else{ans += cnt0;if (a[i] != ans){cout << "! IMPOSSIBLE" << endl;return;}}}cout << "! " << s << endl;
}
int main()
{std::cin.tie(nullptr)->sync_with_stdio(false);int t;cin >> t;while (t--){solve();}return 0;
}