CF1713C
题目链接:Click here
Solution:
首先我们来证明一个引理:对于所有的\(n\)来说,必然在\([n,2n]\)间存在一个完全平方数\(k\)
我们不妨令\(t=\lceil\sqrt n\rceil\),我们来证明不等式:\(n\le t^2\le2n\)
不等式左边是显然成立的,考虑证明不等式的右边部分,对于\(t\)来说,我们有\(\sqrt n\le t<\sqrt n+1\)
那么就有\(n\le t^2 < n+2\sqrt n+1\),我们希望\(n+2\sqrt n+1\le2n\),问题便能迎刃而解
通过计算,我们可以知道当\(n\ge 6\)时有\(n+2\sqrt n+1\le2n\),接下来我们依次检验\(n=1,2,3,4,5\)即可
有了这个引理,我们就可以轻松的完成这道题了,考虑从后往前填数,对于\(h\)来说,我们在\([h,2h]\)找到完全平方数\(k\),有\(h\le k \le 2h\),此时我们考虑对区间\([k-h,h]\)来填数,对于\(k-h\le i \le h\),我们有\(h\ge k-i \ge k-h\),那么我们可以令\(p_i=k-i\),再令\(h=k-h-1\)递归的来做即可
对于每一段区间来说,\(k\)是确定的,\(i\)是不同的,因此保证了区间内的\(p_i\)是互不相同的,同时每一段\(p_i\)的取值范围保证了不同区间的\(p_i\)也不同,于是我们的整个序列刚好是\(0\sim n-1\)的一个排列
#include<bits/stdc++.h>
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void solve(){
vector<int> ans;
int n=read(),i=n-1;
while(i>=0){
for(int j=2*i;j>=i;j--){
int v=sqrt(j),g=j-i;
if(j==v*v){
while(1){
ans.push_back(j-i);
--i;if(i<g) break;
}
j=2*i;
}
}
}
for(int i=n-1;i>=0;i--)
printf("%d ",ans[i]);
printf("\n");
}
signed main(){
int t=read();
while(t--){
solve();
}
return 0;
}