【Codeforces】Codeforces Round #836 (Div. 2) C. Almost All Multiples | 贪心

336 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【Codeforces】Codeforces Round #836 (Div. 2) C. Almost All Multiples | 贪心

题目链接

Problem - C - Codeforces

题目

Given two integers n and x, a permutation p of length n is called funny if pip_i is a multiple of i for all 1in1≤i≤n, and pn=1,p1=xp_n=1,p_1=x.

Find the lexicographically minimal funny permutation, or report that no such permutation exists.

A permutation of length n is an array consisting of each of the integers from 1 to n exactly once.

Let a and b be permutations of length n. Then a is lexicographically smaller than b if in the first position i where a and b differ, ai<bia_i<b_i. A permutation is lexicographically minimal if it is lexicographically smaller than all other permutations.

题目大意

给定两个整数 nnxx,一个有趣的排列 p1,p2,p3,...,pnp_1,p_2,p_3,...,p_n 需要满足以下条件:

  • 对于 1in1\le i\le npip_iii 的倍数。
  • pn=1p_n=1
  • p1=xp_1=x

如果对于给定的 nnxx,存在满足上述条件的有序排列,则输出其中字典序最小的那一个。否则报告不存在这样的排列。

排列:长度为 nn 且其中从 11nn 的每一个整数恰好出现一次。

字典序:设 aabb 是长度为 nn 的排列,则如果在 aabb 不同的第一位置 ii 上,有 ai<bia_i<b_i,则 aa 的字典序小于 bb。如果一个排列的字典序小于所有其他排列,则它字典序最小。

思路

最初我们令 pi=ip_i=i 时,满足对于 1in1\le i\le npip_iii 的倍数,且字典序是所有排列中最小的。我们让 pn=1,p1=xp_n=1,p_1=x 后,容易发现如果 xx 不是 nn 的倍数,一定不可能找到一个位置 adradr,满足:

  • adradrnn 的因数,nn 可以放在 padrp_{adr}
  • adradrxx 的倍数,xx 可以放在 pxp_x

所以我们报告无解。

如果 xnx\mid n,我们可以首先令 px=np_x=n,然后试图把 nn 向后移。遍历后续数组,一旦存在位置 ii 满足 (xi)(in)(x\mid i)\land (i\mid n),就交换 pxp_xpip_i,并令 x=ix=i 试图让 nn 继续后移。

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <map>
#include <vector>
#include <string.h>
#include <queue>
using namespace std;
using LL=long long;
const int N=500001;
const LL mod=1000000007;
int n,m,k,x,y,z,tot,a[N],b[N];
char ch[N];
LL gcd(LL x,LL y) {return y==0?x:gcd(y,x%y);}

LL solve()
{
	scanf("%d",&n);
	scanf("%d",&k);
	if (n%k) return printf("-1\n");
	for (int i=1;i<=n;++i) a[i]=i;
	a[1]=k;
	a[k]=n;
	a[n]=1;
	for (int i=k+1;i<n;++i)
	{
		if (n%i==0&&i%k==0)
		{
			a[k]=i;
			a[i]=n;
			k=i;
		}
	}
	for (int i=1;i<=n;++i) printf("%d ",a[i]);
	printf("\n");
	return 0;
}
int main()
{
	int T=1;
	scanf("%d",&T);
	while (T--) solve();
	return 0;
}