目录
题目:
题目描述:
对于每个案例,给你一个 n
目标:让你找出 1 到 n 的全排列的一种,使得里面所有区间的素性个数总和最多。
判断一个区间 ( l , r ) 是否为素性,看 MEX( )是否为素数,即是看他缺少的数中的最小正整数是否为素数( 如:1 5 4 2 缺少的最小正整数为 3 ,是素数即这个区间具有素性 )。
思路:
这道题上手先试试,我们会发现,1 的位置非常重要,如果一个区间没有 1 的话,那么最小正整数就是 1 ,必定不是素性区间。所以我们尽可能让更多的区间拥有 1 ,那么 1 就应该放在中间(即 n / 2 + 1 的位置),此时拥有1的区间个数是最多的。
为什么这个时候包含 1 的区间是最多的?请看下图
我取 1 左边的任意一个括号和 1 右边的任意一个括号都能形成一个包含 1 的区间,所以
包含1的区间总数 = ( 1 左边个数 + 1 )*( 1 右边个数 + 1 )
在 1 左右个数的和一定的情况下那一定是 “ 差小积大 ” 啦,所以 1 左边有 n / 2 个数的时候包含 1 的区间个数最多(即 1 要放到 n / 2 + 1 的位置)
除此之外,我们发现 2 ,3 都是质数,所以如果区间再有 1 的情况下缺少 2 或 3 ,必定就是素性区间。所以为了更难让区间里面有 2 或 3 ,我们应该把 2 ,3 放两边。在这样的情况下( 2 ... 1 ... 3 )包含 1 的区间中只有长度为 n 的时候(即此时区间的最小正整数为 n + 1 时)可能不满足条件,其他都是素性区间,发现此时为最优方案。
思路有了,具体操作请看AC代码
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int main()
{
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
if (n == 1)
{
cout << 1 << '\n';
continue;
}
else if (n == 2)
{
cout << "1 2" << '\n';
continue;
}
else if (n == 3)
{
cout << "2 1 3" << '\n';
continue;
}
cout << 2 << " ";
for (int i = 4; i <= (n + 3) / 2; i++)
cout << i << " ";
cout << 1 << " ";
for (int i = (n + 3) / 2 + 1; i <= n; i++)
cout << i << " ";
cout << 3 << '\n';
}
return 0;
}