ORZ 。。。UOJ群里面的各位大爷。。。
当时关注这道题主要是因为准备Pkusc的考试。。。然而只会爆搜心塞了我一个星期QAQ
这道题找规律的困难点在于存再多解,并且解的数目非常非常多所以搜起来肉眼基本找不出规律
但是如果知道解答验证起来还是非常容易。。。
当n=4k+2或4k+3时无解
当n=4k时,构造数列:2k+1, [4k ~ 3k+2], [3k ~ 2k+2], [2k ~ k+1], 3k+1, [k ~ 1]
当n=4k+1时,将4k时的数列第一项改成4k+1, 最后加一项2k+1
贴两份代码,一份是N在300以下可以出(但是一些数字会非常慢)的信仰爆搜(搜的时候是按照绝对值的条件由大到小来的,因为绝对值越大存在的方案就越少,比如绝对值等于N-1就只有“1填到N”和“N填到1”两种情况,比普通爆搜快很多),另一份是AC代码。
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define MAXN 1005
int N;
int v[MAXN],A[MAXN];
bool run(int now)//now就是现在需要满足的绝对值条件
{
if(now==-1)return true;
else
{
for(int i=1;i<=N;i++)if(!A[i])
{
if(i-now>=1 && i-now<=N)
{
if(!v[i-now])
{
v[i-now]=true;
A[i]=i-now;
if(run(now-1))return true;
A[i]=0; v[i-now]=false;
}
}
if(i+now>=1 && i+now<=N)
{
if(!v[i+now])
{
v[i+now]=true;
A[i]=i+now;
if(run(now-1))return true;
A[i]=0; v[i+now]=false;
}
}
}
return false;
}
}
int main()
{
while(scanf("%d",&N)==1)
{
for(int i=0;i<=N;i++)v[i]=0;
memset(A,0,sizeof(A));
if(N%4==0)
{
run(N-1);
for(int i=1;i<=N;i++)printf("%d ",A[i]);
putchar('\n');
}
else if(N%4==1)
{
run(N-1);
for(int i=1;i<=N;i++)printf("%d ",A[i]);
putchar('\n');
}
else
{
printf("0\n");
}
}
return 0;
}
#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int main()
{
int N,k;
while(scanf("%d",&N)==1)
{
if(N%4==0)
{
k=N/4;
printf("%d ",2*k+1);
for(int i=4*k;i>=3*k+2;i--)printf("%d ",i);
for(int i=3*k;i>=2*k+2;i--)printf("%d ",i);
for(int i=2*k;i>=k+1;i--)printf("%d ",i);
printf("%d ",3*k+1);
for(int i=k;i>=1;i--)printf("%d ",i);
}
else if(N%4==1)
{
k=(N-1)/4;
printf("%d ",4*k+1);
for(int i=4*k;i>=3*k+2;i--)printf("%d ",i);
for(int i=3*k;i>=2*k+2;i--)printf("%d ",i);
for(int i=2*k;i>=k+1;i--)printf("%d ",i);
if(k)printf("%d ",3*k+1);
for(int i=k;i>=1;i--)printf("%d ",i);
if(k)printf("%d ",2*k+1);
}
else
{
printf("0");
}
putchar('\n');
}
return 0;
}