定义幸运数字为十进制表示下只有 4 和 7 ,并且 4 和 7 的个数一样多的数。
求不小于 n 的最小幸运数字 n≤1018
(这是我称为数位贪心的一个题
首先显然的是一个幸运数字的位数一定是偶数
所以如果给出的 n 的位数是奇数的话,可以直接构造一个 444...777 作为答案
如果是偶数的话
依然是从高位到低位考虑
记录当前的位置 pos ,剩下的 4 的个数,剩下的 7 的个数,是否卡到下界 bnd
这样根据 n 在当前位的那个数,可以找到状态之间的转移
值得注意的是在当前位放下 4 之后如果返回的值为 false ,即后面没有合法的情况,则还需要尝试放下 7 ,如果放下 7 之后后面没有合法的情况,则直接返回 false 即可
另外在放下 4 或者 7 的时候要注意 4 或者 7 的个数是不是足够
我是代码的昏割线
#include<cstdio>
using namespace std;
#define LL long long
int arr[30];
int anser[30];
void outans(int len){
for(int i=0;i<len/2;i++){
printf("4");
}
for(int i=0;i<len/2;i++){
printf("7");
}
}
int lenth(LL v){
int ret = 0;
while(v){
arr[ret++] = v % 10;
v /= 10;
}
return ret;
}
bool ans(int pos,int ll,int lr,bool bnd){
if(pos < 0)
return true;
if(!bnd){
if(ll){
anser[pos] = 4;
return ans(pos-1,ll-1,lr,bnd);
}
else{
anser[pos] = 7;
return ans(pos-1,ll,lr-1,bnd);
}
}
else{
bool flag;
if(arr[pos] < 4 && ll){
anser[pos] = 4;
return ans(pos-1,ll-1,lr,false);
}
if(arr[pos] == 4 && ll){
anser[pos] = 4;
flag = ans(pos-1,ll-1,lr,true);
if(flag)
return true;
}
if(lr==0)
return false;
if(arr[pos] < 7){
anser[pos] = 7;
return ans(pos-1,ll,lr-1,false);
}
if(arr[pos] == 7){
anser[pos] = 7;
return ans(pos-1,ll,lr-1,true);
}
return false;
}
}
int main(){
LL v;
int T;
scanf("%d",&T);
while(T-- && ~scanf("%I64d",&v)){
int len = lenth(v);
if(v <= 0){
puts("47");
continue;
}
if(len % 2){
outans(len+1);
puts("");
}
else{
if(ans(len-1,len / 2,len / 2,true)){
for(int i=len-1;i>=0;i--){
printf("%d",anser[i]);
}
}
else{
outans(len+2);
}
puts("");
}
}
return 0;
}
然而其实这个题只要把所有符合条件的幸运数都求出来,然后每次二分就好了