题目链接:http://codeforces.com/contest/915/problem/C
题目大意:
输入两个正整数a, b。你可以重组a的每一位。让a<=b。求a的最大值。一定有满足的解。
思路:
如果长度不同,输出a的最大值就可以了。
或者:
对于a的前缀没有小于b的前缀时。对于现在的取值要么是a[i]=b[i],或者a[i]=b[i]-1。如果对于a的前缀已经小于b的前缀时,那么后面就优先取最大的数。
时间复杂度O(2^n), n:数字位数。
方法二:
如果n>100这题就不能用这个方法了,有一个O(n^2)的算法。
如果长度不同,输出a的最大值就可以了。
或者:我们去贪心的确定每一位就可以了。
先排个序。
确定第i位,我们只要保证后面为升序。找到最大的第i位的取值。再确定下一位。
方法一:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL a, b, c=0;
multiset<int> st;
vector<int> v;
void pt(){
cout<<"size:"<<st.size()<<endl;
for(multiset<int>::iterator p=st.begin(); p!=st.end(); ){
printf("%d ", *p);
p++;
}
printf("\n");
}
int dfs(int i, int n ,LL b, LL s, int vis){
if(i==n-1){
if(s<=b){
c=max(c, s);
}
return 0;
}
if(vis){
multiset<int>::iterator p=st.end();
p--;
int t=*p;
st.erase(st.find(t));
dfs(i-1, n, b, s*10+t, vis);
st.insert(t);
return 0;
}
multiset<int>::iterator p=st.lower_bound(v[i]);
if(p==st.end()){
p--;
}
if(*p==v[i]){
int t=*p;
st.erase(st.find(t));
dfs(i-1, n, b, s*10+t, 0);
st.insert(t);
p=st.lower_bound(v[i]);
if(p!=st.begin()){
p--;
if(i==0&&*p==0){
return 0;
}
int t=*p;
st.erase(st.find(t));
dfs(i-1, n, b, s*10+t, 1);
st.insert(t);
}
}else{
if(*p>v[i]&&p!=st.begin()){
p--;
}
int t=*p;
st.erase(st.find(t));
dfs(i-1, n, b, s*10+t, 1);
st.insert(t);
}
}
int main()
{
scanf("%lld", &a);
scanf("%lld", &b);
LL cb=b;
while(a){
st.insert(a%10);
a/=10;
}
int Len=0;
while(b){
v.push_back(b%10);
b/=10;
}
if(v.size()>st.size()){
multiset<int>::iterator p=st.end();
p--;
for(; ; p--){
printf("%d", *p);
if(p==st.begin()){
break;
}
}
}
else{
dfs(v.size()-1, 0, cb, 0, 0);
printf("%lld\n", c);
}
return 0;
}
方法二:
#include<bits/stdc++.h>
using namespace std;
char a[20],b[20],c[20];
int main()
{
int m;
while(cin>>a>>b)
{
m=strlen(a);
sort(a,a+m);
if(m<strlen(b))
{
for(int i=m-1; i>=0; i--)
cout<<a[i];
return 0;
}
strcpy(c,a);
for(int i=0; i<m; i++)
{
strcpy(a,c);
for(int j=i; j<m; j++)
{
swap(a[i],a[j]);
if(strcmp(a,b)!=1){
strcpy(c,a);
}
}
}
puts(a);
}
return 0;
}