codeforces 题目 Build Permutation

目录

题目:

题目描述:

思路:

AC代码:


题目:

题目描述:

给你一个 n ,你需要找到一种 0 到 n-1 的全排列方式排到数组的第 0 到 n-1 位。使得数组的任意一位的 下标 加上 下标位置存放的数 的 和 都是 完全平方数 

( 下标 + 下标位置的数 == “一个完全平方数” )

思路:

观察样例,一些答案后面的输出似乎有倒序的身影,所以从这里入手。

为什么倒序?我们可以找一个特例来理解(当 n == 5 时)

所以 n == 5 时,我们需要填写的是 0 到 4 ,而 4 是一个完全平方数,我们只用按照4 3 2 1 0的方式排列,序列跟下标互补之后就都会变成 4 ,此时满足题目要求。

那一般的序列怎么解决?

我们可以尝试局部倒序。其实就是样例 3 的情况。

可以推断出操作过程是这样的:

通过要填写的最大数(设为x),找到大于等于这个数的完全平方数(设为upper),然后我们就可以把 x 放到(upper - x)下标处,这样保证了x放到这个位置的时候,与下标的和是upper,而upper就是完全平方数。

同时,随着下标增加,我们放置的数减少,依然能保证他们的和都是upper,直到将(upper - x)这个数放到x位置停止。

然后我们再将 x 更新为(upper - x - 1),开始新一轮的放置,直到 x < 0 

真是妙啊。

然后我们需要考虑两个问题,真的是所有的 n 都可以找到这样的序列吗?每次将 x 更新之后还能把 x 放到(upper - x)的位置吗?会不会(upper - x)不在 0 到 x 的范围内?

其实不难证明,假设我们现在要填入的最大的数是 x ,如果 x 是 0 ,那么不难证明,序列 0 就是答案。如果x不是 0 ,那么x必定在两个完全平方数之间(左开右闭)

不妨设小于 x 的完全平方数是 a^2 ,那么大于等于 x 的完全平方数自然是 (a+1)^2 

所以:

a^2<x\leq(a+1)^2

upper = (a+1)^2

0 \leq upper - x \leq 2a

当 x = (a+1)^2时,upper - x 有最小值 0 

当 x = a^2+1 时,upper - x 有最大值为 2a

但 2a \leq a^2+1 在 a 取任何值的情况下都成立

所以得出结论:(upper - x)一定会在 0 到 x 的范围内!

我们终于可以放心的写代码了!

思路有了,具体操作请看AC代码

AC代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 1e5 + 5;

int a[N];

int main()
{
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	int t;
	cin >> t;

	while (t--)
	{
		int n;
		cin >> n;

		n--;//虽然给你n,但是我们只用填到n-1

		int tt = n;//代表着要填入的数,
		int x = n;//填完之后还剩的最大的数


		while (x >= 0)
		{
			int temp = sqrt(x);

			if (temp * temp == x)
			{
				for (int i = 0; i <= x; i++)
					a[i] = tt--;
			}
			else
			{
				int upper = (temp + 1) * (temp + 1);

				for (int i = upper - x; i <= x; i++)
					a[i] = tt--;
			}
			x = tt;
		}

		for (int i = 0; i <= n; i++)
			cout << a[i] << " ";
		cout << '\n';
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值