Luogu P11132 【MX-X5-T4】「GFOI Round 1」epitaxy 题解
P11132 【MX-X5-T4】「GFOI Round 1」epitaxy
基于次大值的构造。
考虑到如果最大值和次大值都出现那么结果一定为 \(1\)。而如果次大值在序列中出现 \(2m-1\) 次,则一定会与最大值一起出现,这是不好的。
因此,我们构造把次大值放在序列开头,之后最大值必须要放在前 \(m\) 个位置。这中间有 \(m-2\) 个空位,我们填上 \(n-2\sim n-m-1\),剩下的位置需要填入一个 \(1\sim n-m\) 的排列,这是一个完全相同的子问题。
如果我们不把空位填上 \(n-2\sim n-m-1\),就是希望能更改答案序列中的值。而这种更改上述构造方式也能做到,所以直接这样构造是没有问题的。另外,也可以把次大值放在序列结尾,但是只是改变一个方向,本质相同。如果不把次大值贴紧开头,与这个构造也是等价的,但变得不好处理。
我们发现答案序列中的数构成等差序列且公差为 \(n\) 的约数时才能更新答案,所以我们枚举公差,按照上述方式构造即可。
注意有可能 \(m\) 过大,最小值不能出现 \(2m-1\) 次,这个时候把最大值放中间就好了。我因为这个边界条件卡了一整场,警示后人。
#include <bits/stdc++.h>
using namespace std;
long long t,n,m,ans=0;
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld",&n,&m);
if(m>n/2)
{
for(int i=1;i<=n/2;i++)printf("%lld ",1ll*i);
printf("%lld ",n);
for(int i=n/2+2;i<=n;i++)printf("%lld ",i-1ll);
}
else
{
bool flag=1;
for(int i=m;i>=2;i--)
if(n%i==0)
{
long long now=n;
flag=0;
while(now>0)
{
printf("%lld ",now-1);
for(int j=1;j<=i-2;j++)printf("%lld ",now-1-j);
printf("%lld ",now);
now-=i;
}
break;
}
if(flag)for(int i=1;i<=n;i++)printf("%lld ",i);
}
printf("\n");
}
return 0;
}

浙公网安备 33010602011771号