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;
}

posted @ 2022-08-12 14:42  DQY_dqy  阅读(23)  评论(0编辑  收藏  举报