# PRIMEPERM - Editorial

Author: notsoloud
Tester: tabr
Editorialist: iceknight1093

1928

Observation

# PROBLEM:

Given N, construct a permutation of \{1, 2, \ldots, N\} such that |P_i - i| is a prime for every i, or claim that non exist.

# EXPLANATION:

Let’s first try to solve the problem for small values of N.

If N \leq 3, no solution exists.
Otherwise, you can either work out by hand or run a brute-force across all N! permutations, and note that an answer does exist for N = 4, 5, 6, 7. For example:

• [3, 4, 1, 2] for N = 4
• [3, 4, 5, 1, 2] for N = 5
• [3, 4, 5, 6, 2, 1] for N = 6
• [3, 4, 5, 6, 7, 1, 2] for N = 7

In fact, this is already enough to solve the entire problem!

Notice that if a valid permutation of length N exists, then a valid permutation of length N+4 exists as well.
The idea for this comes from the solution for N = 4: pair up (N+1, N+3) and (N+2, N+4), and then using the solution we already have for the first N elements.
That is, set:

• P_{N+3} = N+1
• P_{N+4} = N+2
• P_{N+1} = N+3
• P_{N+2} = N+4

For each of these indices, the difference between i and P_i is 2, which is indeed a prime; so they’re taken care of.
By continually extending by 4 in this fashion, we obtain a solution for any N \geq 4.

As an example, a solution for N = 13 would look as follows:

• Start with N = 5, and P = [3, 4, 5, 1, 2]
• Add in the next 4 elements using the above strategy, to obtain P = [3, 4, 5, 1, 2, \underline{8, 9, 6, 7}]
• Once again add in the next 4 elements, to obtain P = [3, 4, 5, 1, 2, 8, 9, 6, 7, \underline{12, 13, 10, 11}]
This is the final permutation we’re looking for.

# TIME COMPLEXITY

\mathcal{O}(N) per testcase.

# CODE:

Tester's code (C++)
#include <bits/stdc++.h>
using namespace std;

struct input_checker {
string buffer;
int pos;

const string all = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const string number = "0123456789";
const string upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string lower = "abcdefghijklmnopqrstuvwxyz";

input_checker() {
pos = 0;
while (true) {
int c = cin.get();
if (c == -1) {
break;
}
buffer.push_back((char) c);
}
}

assert(pos < (int) buffer.size());
string res;
while (pos < (int) buffer.size() && buffer[pos] != ' ' && buffer[pos] != '\n') {
res += buffer[pos];
pos++;
}
return res;
}

string readString(int min_len, int max_len, const string& pattern = "") {
assert(min_len <= max_len);
string res = readOne();
assert(min_len <= (int) res.size());
assert((int) res.size() <= max_len);
for (int i = 0; i < (int) res.size(); i++) {
assert(pattern.empty() || pattern.find(res[i]) != string::npos);
}
return res;
}

int readInt(int min_val, int max_val) {
assert(min_val <= max_val);
int res = stoi(readOne());
assert(min_val <= res);
assert(res <= max_val);
return res;
}

long long readLong(long long min_val, long long max_val) {
assert(min_val <= max_val);
long long res = stoll(readOne());
assert(min_val <= res);
assert(res <= max_val);
return res;
}

vector<int> readInts(int size, int min_val, int max_val) {
assert(min_val <= max_val);
vector<int> res(size);
for (int i = 0; i < size; i++) {
res[i] = readInt(min_val, max_val);
if (i != size - 1) {
}
}
return res;
}

vector<long long> readLongs(int size, long long min_val, long long max_val) {
assert(min_val <= max_val);
vector<long long> res(size);
for (int i = 0; i < size; i++) {
res[i] = readLong(min_val, max_val);
if (i != size - 1) {
}
}
return res;
}

assert((int) buffer.size() > pos);
assert(buffer[pos] == ' ');
pos++;
}

assert((int) buffer.size() > pos);
assert(buffer[pos] == '\n');
pos++;
}

assert((int) buffer.size() == pos);
}
};

int main() {
input_checker in;
int tt = in.readInt(1, 1000);
vector<vector<int>> a(8);
for (int n = 4; n <= 7; n++) {
vector<int> p(n);
iota(p.begin(), p.end(), 0);
do {
int ok = 1;
for (int i = 0; i < n; i++) {
int t = abs(i - p[i]);
if (t == 2 || t == 3 || t == 5) {
} else {
ok = 0;
}
}
if (ok) {
a[n] = p;
break;
}
} while (next_permutation(p.begin(), p.end()));
}
int sn = 0;
while (tt--) {
int n = in.readInt(2, 1e5);
sn += n;
if (n <= 3) {
cout << -1 << " \n";
} else {
vector<int> ans;
while (n - (int) ans.size() >= 8) {
int t = (int) ans.size() + 1;
for (int i = 0; i < 4; i++) {
ans.emplace_back(a[4][i] + t);
}
}
int s = n - (int) ans.size();
int t = (int) ans.size() + 1;
// cerr << s << " " << t << endl;
for (int i = 0; i < s; i++) {
ans.emplace_back(a[s][i] + t);
}
for (int i = 0; i < n; i++) {
cout << ans[i] << " ";
}
cout << '\n';
for (int i = 0; i < n; i++) {
int t = abs(ans[i] - i - 1);
assert(t == 2 || t == 3 || t == 5);
}
sort(ans.begin(), ans.end());
for (int i = 0; i < n; i++) {
assert(ans[i] == i + 1);
}
}
}
cerr << sn << endl;
assert(sn <= 1e6);
return 0;
}

Editorialist's code (Python)
saved = [ [3, 4, 1, 2], [3, 4, 5, 1, 2], [3, 4, 5, 6, 2, 1], [3, 4, 5, 6, 7, 1, 2] ]

for _ in range(int(input())):
n = int(input())
if n <= 3: print(-1)
else:
ans = [0]*(n+1)
while n > 7:
ans[n], ans[n-2] = n-2, n
ans[n-1], ans[n-3] = n-3, n-1
n -= 4
ans[1:n+1] = saved[n-4]
print(*ans[1:])


Solution: 1053765992 (codechef.com)

I am using a sieve to precompute the primes and I am checking from 2 to N, a number with which if a permutation is shifted this condition will be satisfied i.e the difference of value and index becomes a prime. I don’t understand why this gives a WA?
Can anyone let me know with an example where this might fail?

Nvm I just tried looping to see which N it fails, and it can’t find such a number when N = 11 but there exists a permutation, so this method fails.