1. 程式人生 >實用技巧 >其它 >限制不互素對的排列

限制不互素對的排列


連結:https://ac.nowcoder.com/acm/contest/9981/I
來源:牛客網

題目描述
輸入一個數n,請構造一個長度為n的排列,使得其中正好有k對相鄰的數gcd(最大公約數)大於1。
排列是指1到n一共n個數,每個數都出現過且僅出現過1次。
輸入描述:
兩個整數n和k,用空格隔開。

限制不互素對的排列

輸出描述:
如果不存在可行的構造方案,輸出-1。
否則輸出一行n個數,用空格隔開。如果有多組可行的構造方案,輸出任意一組即可。

示例1
輸入
2 1
輸出
-1
說明
長度為2的排列有2個:{1,2}和{2,1},顯然都不符合題意

示例2
複製
6 3
輸出
5 3 6 2 4 1
說明
共有3對相鄰數不互素:{3,6}、{6,2}和{2,4}。
這並不是唯一解,只要構造任意合法解即可。

思路:

限制不互素對的排列


注意k的範圍正好是n/2,而且在1-n正好有n/2個偶數,所有的偶數公約數都包含2大於1,也就是說n以內偶數可以組成n-1組我們要求的組數。

然後按照這個思路,我們可以做一個分類,小於4,4-5,大於等於6。小於4的時候是沒有gcd大於1的,4-5是有一組gcd大於1。可以舉例輸出。

然後大於等於6,k大於等於3時,我們可以控制輸出的偶數的數目來控制滿足的組數。假如n=8;k=4;{3 6 2 4}這裡面有三組,但是k是4,所以我們再輸出一個8, {3 6 2 4 8}就滿足k的條件了,而且我們也可以發現,相差為2的奇數,gcd一定為1,相差為1的數,gcd也一定為一,所以後面的數我們直接按照順序輸出就可以了。

注意:
1.當k=n/2的時候需要特判一下不然就會輸出n+1個數
if(p!=n/2) printf(" %d", n);

2.當k等於0的時候任何n都滿足,可以在最前面判斷一下,特別是在小於4的範圍特別容易漏掉。

程式碼:

#include<stdio.h>

int main()
{
	int n, k;
	scanf("%d%d", &n, &k);
	if(n<4) 
	{
		if(k==0)
		{
			for(int i=1; i<n;i++)
				printf("%d ", i);
			printf("%d", n);
		}
		else
			printf("-1");
	}
	else if(n<=5)
	{
		if(k==0)
		{
			for(int i=1; i<n;i++)
				printf("%d ", i);
			printf("%d", n);
		}
		else if(k==1)
		{
			printf("1 3 2 4");
			if(n==5) printf(" %d", n);
		}
		else if(k==2)
			printf("-1");
	}
	else
	{
		if(k==0)
		{
			for(int i=1; i<n;i++)
				printf("%d ", i);
			printf("%d", n);
		}
		else if(k==1)
		{
			printf("1 3 2 4");
			for(int i=5; i<=n;i++)
				printf(" %d", i);
		}
		else if(k==2)
		{
			printf("2 3 6 4 1 5");
			for(int j=7; j<=n; j++)
				printf(" %d", j);
		}
		else
		{
			int i, p;
			printf("3 6 2 4");
			p=k;
			k-=3;
			for(i=8; k>0; k--,i+=2)
			{
				printf(" %d", i);
			}
			printf(" 1");
			for(int j=5; j<i&&j<=n; j+=2)
				printf(" %d", j);
			for(int j=i; j<n; j++)
				printf(" %d", j);
			if(p!=n/2)
				printf(" %d", n);
		}
	}
	return 0;
}