UPC-吉利数字
题目描述
Farmer John马上就要过生日了,奶牛们想给他送一份礼物。由于预算不足,奶牛们打算把对Farmer John的爱寄托在一个数字中。奶牛们知道Farmer John认为的吉利的数字有m(1 ≤ m ≤ 10) 个,也就是阿拉伯数字0到9这十个数的一个子集。如果一个正数没有前导零,且其中的每一位都是Farmer John认为的吉利的数字,那么这个数就是一个吉利数。
考虑到Farmer John生日那天是农场建立的第n天,奶牛们希望用这m个数生成一个不超过n且最接近n的一个吉利数,把它送给Farmer John。奶牛们没想到n实在太大了,所以她们请你帮忙计算一下这个礼物是多少。
输入
输入包含两行,第一行包含两个整数n和m
第二行包含m个整数,每个数都是0到9中的一个。数据保证这m个整数互不相同
输出
仅一行,即不超过n的最大的吉利数
如果无解,请输出-1
Sample Input
2019 2
1 9
Sample Output
1999
这题的最初来源是海淀区第三届智慧杯编程思维类复赛(C++)
原题解用贪压和递归,咱也没整明白。所以还是自己做了
听说我写的博客让你们非常的迷茫,所以这一次更新我好好解释以下我的内容吧………………
首先献上自己的贪心加模拟的垃圾代码(我要看题解)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char u[100005],save[11],ans[100005];
bool cmp(char a,char b) {
return a>b;
}
int main() {
int num;
cin>>u;
cin>>num;
for(int i=0; i<num; i++)
cin>>save[i];
sort(save,save+num,cmp);
int l=strlen(u);
if(num==1&&save[0]=='0') {
cout<<"-1"<<endl;
return 0;
}
int i;
for(i=0; i<l; i++)
ans[i]=save[0];
for(i=0; i<l; i++) {
if(ans[i]==u[i])
continue;
if(ans[i]<u[i]) {
int j=0;
if(ans[j]=='0')
j++;
if(j>=l)
{
cout<<"-1"<<endl;
return 0;
}
for(; j<=i; j++)
putchar(ans[j]);
for(int j=i+1; j<l; j++)
putchar(save[0]);
cout<<endl;
return 0;
}
int temp=0;
while(ans[i]>u[i]) {
if(temp>num-1)
goto A;
ans[i]=save[temp++];
}
i--;
}
cout<<ans<<endl;
return 0;
A:
for(int j=i-1; j>=-1; j--) {
if(j==-1) {
l--;
if(!l) {
cout<<-1<<endl;
return 0;
}
for(i=0; i<l; i++)
putchar(save[0]);
putchar('\n');
return 0;
}
if(ans[j]==save[num-1])
continue;
if(ans[j]!=save[num-1]) {
for(int k=0; k<num; k++)
if(ans[j]==save[k]) {
ans[j]=save[k+1];
for(int z=0; z<=j; z++)
putchar(ans[z]);
for(int z=j+1; z<l; z++)
putchar(save[0]);
putchar('\n');
return 0;
}
}
}
}
OK,思路就是贪心,自己拿个笔戳一戳也能看出来门道。
下面按照种花家的亲们的要求,来做一下解释;
首先整体思路如下:
1、先填入如果可以的最大值(不是真的最大值,只是最理想的最大值)
PS:接下来的这个数和原来的数的含义是指每一位对应的数字.
2、从前往后,如果有一位数是比原来的数小的话,那么从这个数之后的所有数字都是最大值
3、如果一个数比原来的数大,那么就让他降到所有的可填充数中最大的且不大于原来数字的数字。如果都无法实现,那么就往前面找,是否有一个数字不是填充数字中最小的。(因为如果不是最小的可填充数就可以让这个填充数往下减少)如果都是,那么位数减少一,剩下的全部以可填充数字最大值输出。
4、特殊考虑如果位数只有一个,而且可能出现前导0的情况!
然后思路有了,接下来就是纯模拟了。模拟起来有点复杂,所以一定要捋清思路,不要迷茫!
By-轮月