赛时做法,AC,思路比较清奇。
具体思路就是让每个数尽可能产生贡献,先输出p的整数倍,然后再尽可能让每个数产生贡献。枚举每个非p的整数倍的数,然后尽可能输出能和它相加成p的整数倍的数,当然我们希望尽可能延续,所以需要记录一个pos
我不会证明,看了一下讨论区都没有这么做的,代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010;
int T;
void print(int n)
{
for(int i=1;i<=n;i++) cout<<i<<" ";
cout<<endl;
}
int vis[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--)
{
memset(vis,0,sizeof(vis));
int n,p;
cin>>n>>p;
int maxn = -1;
if(p == 1 || n+n-1 < p){ print(n); continue;}
for(int i=1;i;i++)
{
if(p*i > n)
{
maxn = p*(i-1);
break;
}
if(p*i <= n){ cout<<p*i<<" ";vis[p*i] = 1;}
}
for(int i=1;i<=n;i++)
{
if(!vis[i] && i%p != 0)
{
cout<<i<<" ";
vis[i] = 1;
int last;
for(int j=1;j;j++)
{
if(p*j-i > n) break;
if(!vis[p*j-i] && p*j-i > 0)
{
cout<<p*j-i<<" ";
vis[p*j-i] = 1;
last = p*j-i;
for(int k=1;k;k++)
{
if(p*k-last > n) break;
if(p*k-last > 0 && !vis[p*k-last])
{
vis[p*k-last] = 1;
cout<<p*k-last<<" ";
last = p*k-last;
}
}
}
}
}
}
for(int i=1;i<=n;i++) if(!vis[i]) cout<<i<<" ";
cout<<endl;
}
}