【LGR-152-Div.2】洛谷 8 月月赛 Ⅲ &「TAOI」Round 2 T1 题解

· · 题解

题意

给定正整数 pn。对于一个排列,我们称其中相邻两项产生「共振」当且仅当这两个数的和为 p 的倍数。

请你构造一个 1 \sim n 的排列,最大化其中产生「共振」的次数。如果有多种方案,输出任意一种即可。

思路

Subtask 1

直接暴力枚举所有可能的排列的情况,并选择「共振」的次数最大的一种方案并输出。

时间复杂度 O(Tn!)

Subtask 2

因为要产生「共振」,且 p=2,所以要尽量使奇数和奇数放在一起,偶数和偶数放在一起,使得相邻数之和能够被 2 整除,进而使得产生「共振」的次数最大。

产生「共振」的最大次数为 n-2。因为一共有 n-1 个「相邻组」(即相邻两数组成的二元组),而肯定有一个「相邻组」是一边奇数、一边偶数。

例如:n=9,p=2

正确的序列可以是 1,3,5,7,9,2,4,6,8

Subtask 3

这个子任务满足 p=3

我们可以将模 31 的数和模 32 的数交替着放。最后放能够被 3 整除的数。

不难发现,产生「共振」的最大次数为 n-2

例如:n=9,p=3

正确的序列可以是 1,2,4,5,7,8,3,6,9

Subtask 4

推广 p=3 时的做法,就可以得到正解。

我们可以枚举每一个 i,保证 1\le i< \frac{p}{2},将模 pi 的数和模 pp-i 的数交替着放。

然后放能够被 p 整除的数。

但是,这里有个大坑点!

2\mid p,则我们还没有输出模 p\frac{p}{2} 的数。

我们可以发现,两个模 p\frac{p}{2} 的数的和一定可以被 p 整除,所以把它们放在一起,最大化「共振」的次数。

此时,最多可能有 \lfloor \frac{p}{2}\rfloor 个「相邻组」不产生「共振」。

例如:n=12,p=4

正确的序列可以是 1,3,5,7,9,11,4,8,12,2,6,10

正确的序列可以是 $1,4,6,9,11,2,3,7,8,12,5,10$。 **但是,这里还有问题!** 当 $p$ 足够大时,代码的时间复杂度常数就会非常大。 但是,当 $2n≤p$ 时,**「共振」不可能发生**。 此时,我们就输出 $1,2,3,4,\dots,n-1,n$ 即可。 (蒟蒻在此处看到自己 TLE on #10,还以为自己是没用快读快写才出的问题,但尝试表明,用了也不能 AC,所以在这里卡了很长时间) 另外,在枚举这些配对的数时,**一定要保证它们 $\bm{\le n}$**。不然也有可能出错。 ## 代码 ```cpp #include<bits/stdc++.h> using namespace std; int n,p; inline void solve(){ scanf("%d%d",&n,&p); if(n*2<p){ for(int i=1;i<=n;i++){ printf("%d ",i); } return ; } for(int i=1;i*2<p;i++){ for(int j=0;j<=n;j+=p){ if(i+j<=n) printf("%d ",i+j); if(j+p-i<=n) printf("%d ",j+p-i); } } for(int i=p;i<=n;i+=p){ printf("%d ",i); } if(p%2==0){ for(int i=p/2;i<=n;i+=p){ printf("%d ",i); } } printf("\n"); return; } int T; int main(){ scanf("%d",&T); while(T--) solve(); return 0; } ```