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;
}