http://acm.hdu.edu.cn/showproblem.php?pid=1027
【题意】就是求一个第m小的数列,这里的大小就当是以n+1进制的数字比较;
【题解】我先求出需要改变的起点开始,判断后面每一位的数需要改变的值。最后就按前面求出的值处理(我用线段树查找)。
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,m,f[4001],i,w[1001],u[1001];
void tt(int x,int z,int y,int t)
{
int j;
for(j=1;j<=z;j++)if(j*t>=y)break;
u[x]=--j;
if(x<i)tt(x+1,z-1,y-j*t,t/(z-1));
}
//线段树
//建树
void establish(int p,int x,int y)
{
if(x==y){f[p]=1;return;}
int mid=(x+y)/2;
establish(p*2,x,mid);
establish(p*2+1,mid+1,y);
f[p]=f[p*2]+f[p*2+1];
}
//维护
inline void keep(int x)
{
while(x>=1)f[x]--,x>>=1;
}
//查找
int find(int p,int z,int x,int y)
{
if(y==x){keep(p);return w[x];}
int mid=(x+y)/2;
if(f[p*2]>=z)return find(p*2,z,x,mid);
else return find(p*2+1,z-f[p*2],mid+1,y);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int t=1;
for(i=1;i<=n;i++)
if(t>m)break;else t*=i;
i--;if(i!=0)t/=i;
tt(1,i,m,t);
if(n-i>=1)
{
printf("%d",1);
for(int j=2;j<=n-i;j++)printf(" %d",j);
}
//这以前一直是在求需要改变的量;
int k=0;
if(n-i>=1)printf(" %d",u[1]+n-i+1);
else printf("%d",u[1]+n-i+1);
for(int j=n-i+1;j<=n;j++)
if((u[1]+n-i+1)!=j)w[++k]=j;
sort(w+1,w+1+k);//排序;
if(k>=1)
{
establish(1,1,k);
for(int j=2;j<=i;j++)printf(" %d",find(1,u[j]+1,1,k));
}
printf("\n");
}
return 0;
}