题解: [ARC144C] K Derangement
我是打表仙人。显而易见的有当 \(2k > n\) 时非法。让我们打个暴力代码出来。(此处省略一份 \(O(n!)\) 暴力代码)让我们试试 6 3
的输出结果:4 5 6 1 2 3
。再让我们试试 12 3
的输出结果:4 5 6 1 2 3 10 11 12 7 8 9
。是不是有点初见端倪?再来一组:8 2
的输出:3 4 1 2 7 8 5 6
。现在你可以看出规律了。把 \(n\) 分成几段长度为 \(2k\) 的段,每段结构为:
\[2k \times x + k + 1,2k \times x + k + 2,2k \times x + k + 3,...,2k \times x + k + k, \\
2k \times x + 1,2k \times x + 2,2k \times x + 3,...,2k \times x + k
\]
其中 \(x\) 表示这是第几段,从 \(0\) 开始计数。但是这是 \(2k \mid n\) 的情况。
那么 \(2k \nmid n\) 呢?试试 8 3
。输出为 4 5 6 7 8 1 2
。再来 10 3
。输出为 4 5 6 1 8 9 10 2 3 7
。多打几组,你会发现,前面 \([1,n - 2k]\) 平安无事,依然是上面的规律。直到 \(n - 2k + 1\) 这个位置。我们发现它输出了 \([n - 2k + 1,n - k]\) 的 \(k\) 个数,究其原因是,如果都到这了还按照原来的规律输出,最后几个一定是 \(p_i = i\) 不合法的。所以我们需要提早把它输出以避免非法情况。至于最后的 \(k\) 个数,把没输出的按照大小输出即可。可以证明一定合法。
code:
#include<bits/extc++.h>
#define int long long
using namespace std;
const int maxn = 3e5 + 5;
int n,k;
int p[maxn];
bool b[maxn];
vector<int>ans;
signed main()
{
scanf("%lld%lld",&n,&k);
if ((k << 1) > n)
return printf("-1"),0;
fill(b + 1,b + n + 1,1);
for (int s = 1; s + (k << 1) - 1 <= n && ans.size() < n - (k << 1); s += (k << 1))
{
int t = s + (k << 1);
for (int i = s + k; i < t && ans.size() < n - (k << 1); i++)
{
b[i] = 0;
ans.push_back(i);
}
for (int i = s; i < s + k && ans.size() < n - (k << 1); i++)
{
b[i] = 0;
ans.push_back(i);
}
}
for (int i = n - k + 1; i <= n; i++)
{
b[i] = 0;
ans.push_back(i);
}
for (int i = 1; i <= n; i++)
if (b[i])
ans.push_back(i);
for (auto i : ans)
printf("%lld ",i);
return 0;
}
本文来自博客园,使用 CC BY-NC-SA 4.0 协议。
作者:伊埃斯,转载请注明原文链接:https://www.cnblogs.com/Eous/articles/18741918