题意
题目传送门
思路
先从部分分开始考虑。
k=0
当 k=0 时,不存在一个数是另外一个数的的倍数,考虑到 a 中的最大值不超过 2n-1,若我们输出 n\sim 2n-1,则刚好满足要求。
k\le n-1
当 k=0 时同上,而 k=n-1 时我们输出 1 和 n\sim 2n-2 即可,接下来考虑 1\le k<n-1 即可。
注意到若恰好有 2 个相同的数 x 且满足 x\ge n,则它们互相可以有 1 对倍数关系,所以当 k=1 或 k=2 时,我们输出 k 对相同的大于等于 n 的数即可。同时可以发现若恰好有 3 个相同的数 x 且满足 x\ge n,则它们互相可以有 3 对倍数关系,所以当 k=3 时我们输出 3 个相同的大于 n 的数即可。
那要是 k\ge 4 呢?我们可以输出 \left\lfloor\frac{k}{3}\right\rfloor 次 3 个相同的数(每次输出的数不能相同),这样就可以保证剩下的 k\le 2,再按照 k\le 2 的方式输出即可。
正解
从上一个部分分我们已经可以知道一些与正解相关的解法了,接下来把上面的做法推广到 k>n 即可。
当 n-1\le k<(n-1)+(n-2) 时,我们可以先输出 1,因为后面的所有数必然是 1 的倍数,所以必然构成 n-1 对倍数关系,所以使 k\gets k-(n-1),接下来按照 k<n-1 的方式输出即可。
当 (n-1)+(n-2)\le k<(n-1)+(n-2)+(n-3) 时,我们可以在上面的基础上再次输出 1,这个 1 可以与后面的数构成 n-2 对倍数关系,所以在上面的基础上再使 k\gets k-(n-2),然后按照 k<n-1 的方式输出。
从上面的处理方式我们可以发现,若 k\ge\sum_{i=1}^nn-i 且此时的 i 为满足条件的 i 中最大的,则需要输出 i 个 1,然后按照部分分的思路输出即可。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int ans[N];
signed main()
{
int n,k;
cin>>n>>k;
int m=n-1,cnt=1,tot=0;
while(cnt<=n&&k-n+cnt>=0)k-=n-cnt,cnt++,ans[++tot]=1;
while(k>=3)
{
ans[tot+1]=ans[tot+2]=ans[tot+3]=++m;
tot+=3,k-=3;
}
for(int i=1;i<=k;i++)ans[tot+1]=ans[tot+2]=++m,tot+=2;
while(tot<n)ans[++tot]=++m;
for(int i=1;i<=tot;i++)cout<<ans[i]<<' ';
return 0;
}