题意:十进制数n.操作:可以交换n的任意两个digit的位置.
T<=100.1<=n,k<=1e9. 问k次操作后,能得到最小和最大的数字?
贪心:假如要大,当前数字和后面最大数字交换.假如有多种 不一定选最后面的..有反例..
n只有9位数(1e9情况只有一种).暴力枚举全排列(第i位变到第p[i]位),
一个排列到另外一个排列最少的交换次数为:sigma(每个循环节的长度-1).
假如有循环节 1->x->y->...m->1. 那么交换一次(1,x) 则变换为 x->x. 1->y->..->m->1. 交换一次长度减少1.
因为T<=100. 预处理出排列变化的代价. O(n!*(n+T)).
#include <bits/stdc++.h>
using namespace std;
const int N=15;
int T,k,a[N],vis[N];
char n[N];
vector<int> perm[N][N];
void init(){
for(int t=1;t<=9;t++){
for(int i=1;i<=t;i++)
a[i]=i;
memset(vis,0,sizeof(vis));
do{
int now=0,tmp=0;
for(int i=1;i<=t;i++)
now=now*10+a[i];
for(int i=1;i<=t;i++){
if(vis[i]==now) continue;
for(int j=a[i];j!=i;j=a[j])
vis[j]=now,tmp++;
}
perm[t][tmp].push_back(now);
}while(next_permutation(a+1,a+1+t));
}
}
int calc(int mask){
int tmp=1,res=0;
while(mask){
res+=a[mask%10]*tmp;
tmp*=10;
mask/=10;
}
return res;
}
int main(){
init();
scanf("%d",&T);
while(T--){
scanf("%s%d",n,&k);
int t=strlen(n);
if(t==10){
printf("%s %s\n",n,n);
continue;
}
if(k>=t) k=t-1;
for(int i=1;i<=t;i++)
a[i]=n[i-1]-'0';
int mn=1e9,mx=0;
int lj=1;
for(int i=1;i<t;i++)
lj*=10;
for(int i=0;i<=k;i++){
for(auto it=perm[t][i].begin();it!=perm[t][i].end();it++){
int val=calc(*it);
if(val<lj) continue;//lead zero
val<mn?mn=val:0;
val>mx?mx=val:0;
}
}
printf("%d %d\n",mn,mx);
}
return 0;
}