題意很簡單,就是給出n,m求n個數下逆序個數為m的最小排列,求出最小排列。
我用的暴力+貪心的方法。 用m與當前個數(也就是剩下需要寫出的個數)的最大逆序個數進行比較,容易知道當前逆序最大的個數為s=(n)*(n-1)/2;
如果s==m直接逆序打印沒用過的數。如果m<s,那麼繼續用m與s1=(n-1)(n-2)/2,(n-1個最大逆序個數比較),然後找出沒用過的(m-s1+1)個數,即為當前要打印的個數,
如果 m>=s,直接找一個最小沒用過的數打印。
一開始沒用long long還有各種細節不注意錯了好幾次,代碼寫得也很爛,網上好像有其他更簡單的方法。
下面是AC代碼:
[cpp]
#include<iostream>
#include<cstdio>
using namespace std;
int mark[50005];
int main(){
int i,j;
long long n,m,t;
while(cin>>n>>m){
// printf("%I64d\n",m);
if(n==-1&&m==-1)
break;
long long s=n*(n-1)/2;
// cout<<s<<endl;
// printf("%I64d\n",s);
// return 0;
int flag=1;
t=n;
for(i=1;i<=n;i++)
mark[i]=0;
if(m==0){
cout<<1;
for(i=2;i<=n;i++)
cout<<" "<<i;
cout<<endl;
}
else{
while(m){
if(m==s){
for(i=n;i>=1;i--){
if(mark[i]==0){
if(flag){
flag=0;
cout<<i;
mark[i]=1;
}
else{
cout<<" "<<i;
mark[i]=1;
}
}
}
break;
}
else if(m<s){
long long nexts=(t-1)*(t-2)/2;
if(m>nexts){
long long key=m-nexts;
int count=0,k;
for(i=1;i<=n;i++){
if(count==key+1) break;
if(mark[i]==0){
count++;
k=i;
}
}
if(flag){
cout<<k;
flag=0;
}
else{
cout<<" "<<k;
}
mark[k]=1;
m=nexts;
}
else{
for(i=1;i<=n;i++)
if(mark[i]==0){
if(flag){
flag=0;
cout<<i;
mark[i]=1;
break;
}
else{
cout<<" "<<i;
mark[i]=1;
break;
}
}
}
}
t--;
s=t*(t-1)/2;
}
cout<<endl;
}
}
return 0;
}
作者:w00w12l