1713C - Build Permutation

题目链接

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(0in1), 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,,n1] 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(1t104) — 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(1n105) — 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,,pn1(0pin1)— the permutation p
— if the answer exists, and −1otherwise.

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] [sx,x] 这个区间, i + a [ i ] i + a[i] i+a[i] 都可以凑成 s。

接着我们又将 x 更新为 s - x - 1。因为 [ s − x , x ] [s - x,x] [sx,x]区间以及放好合适的数字了,接下来要处理的就是 [ 0 , s − x − 1 ] [0,s - x - 1] [0,sx1] 区间的数了。

这样的话,我们就可以 递归的 来处理子问题。

这个 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;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值