【Poj2825】Perfect Permutation 构造

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值