题目链接
1713C - Build Permutation Rating : 1200
题目描述
A 0-indexed array a of size n is called good if for all valid indices i ( 0 ≤ i ≤ n − 1 ) i (0≤i≤n−1) i(0≤i≤n−1), ai+i is a perfect square†.
Given an integer n. Find a permutation‡ p of [ 0 , 1 , 2 , … , n − 1 ] [0,1,2,…,n−1] [0,1,2,…,n−1] that is good or determine that no such permutation exists.
† An integer x is said to be a perfect square if there exists an integer y such that x=y2.
‡ An array b is a permutation of an array a if b consists of the elements of a in arbitrary order. For example, [4,2,3,4] is a permutation of [3,2,4,4] while [1,2,2] is not a permutation of [1,2,3].
Input
The first line contains a single integer t ( 1 ≤ t ≤ 1 0 4 ) t (1≤t≤10^4) t(1≤t≤104) — the number of test cases.
The only line of each test case contains a single integer n ( 1 ≤ n ≤ 1 0 5 ) n (1≤n≤10^5) n(1≤n≤105) — the length of the permutation p.
It is guaranteed that the sum of n over all test cases does not exceed 1 0 5 10^5 105.
Output
For each test case, output n distinct integers
p
0
,
p
1
,
…
,
p
n
−
1
(
0
≤
p
i
≤
n
−
1
)
p0,p1,…,pn−1 (0≤pi≤n−1)
p0,p1,…,pn−1(0≤pi≤n−1)— the permutation p
— if the answer exists, and −1
otherwise.
inputCopy
3
3
4
7
outputCopy
1 0 2
0 3 2 1
1 0 2 6 5 4 3
大致题意:
给你一个数 n n n,能否构造出一个下标从 0 开始的,长度为 n n n, i + a [ i ] i + a[i] i+a[i] 是一个完全平方数的数组。(数组里面的元素也只能是 0 ~ n-1,每一个元素出现一次)。
可以就打印出该数组。
否则打印 -1
。
分析:
首先我们需要知道一个定理:对于任意的正数 x x x,在区间 [ x , 2 x ] [x,2x] [x,2x] 内至少存在一个完全平方数。证明
通过以下的代码可以求出 [ x , 2 x ] [x,2x] [x,2x] 区间内最大的那个完全平方数。
// x = 7,s = 9; x = 8,s = 16
int s = sqrt(2*x);
s *= s;
所以在 [ s − x , x ] [s - x,x] [s−x,x] 这个区间, i + a [ i ] i + a[i] i+a[i] 都可以凑成 s。
接着我们又将 x 更新为 s - x - 1。因为 [ s − x , x ] [s - x,x] [s−x,x]区间以及放好合适的数字了,接下来要处理的就是 [ 0 , s − x − 1 ] [0,s - x - 1] [0,s−x−1] 区间的数了。
这样的话,我们就可以 递归的 来处理子问题。
这个 x 最终会变为 -1,所以返回的条件就是 x < 0。
时间复杂度: O ( n ) O(n) O(n)
代码:
#include <iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
using PII = pair<int,int>;
const int N = 2e5+10;
int a[N];
void dfs(int r){
//退出条件 r最终会变为 -1
if(r < 0) return;
//求区间 [r,2r] 中的最大的完全平方数 s
int s = sqrt(2*r);
s *= s;
//此时区间 [l,r] 中的 a[i] + i 都凑成 s
int l = s - r;
//由于本层处理的是区间 [l,r]
//所以下一层就处理[0,l-1]
dfs(l - 1);
//将区间 [l,r] 中的 a[i] + i 都凑成 s
for(int i = l,j = r;i <= j;i++,j--){
a[i] = j;
a[j] = i;
}
}
void solve(){
int n;
scanf("%d",&n);
dfs(n - 1);
for(int i = 0;i < n;i++){
printf("%d ",a[i]);
}
puts("");
}
int main() {
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}