HDU 5676 ztr loves lucky numbers(dfs+离线)——BestCoder Round #82(div.1 div.2)

ztr loves lucky numbers

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description
ztr loves lucky numbers. Everybody knows that positive integers are lucky if their decimal representation doesn't contain digits other than 4 and 7. For example, numbers 47, 744, 4 are lucky and 5, 17, 467 are not.

Lucky number is super lucky if it's decimal representation contains equal amount of digits 4 and 7. For example, numbers 47, 7744, 474477 are super lucky and 4, 744, 467 are not.

One day ztr came across a positive integer n. Help him to find the least super lucky number which is not less than n.
 

Input
There are T (1n105)  cases

For each cases:

The only line contains a positive integer  n(1n1018) . This number doesn't have leading zeroes.
 

Output
For each cases
Output the answer
 

Sample Input
   
   
   
   
2 4500 47
 

Sample Output
   
   
   
   
4747 47
 

Source
BestCoder Round #82 (div.2)
 

/************************************************************************/

附上该题对应的中文题

ztr loves lucky numbers

 
 
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
ztr喜欢幸运数字,他对于幸运数字有两个要求
1:十进制表示法下只包含4、7
2:十进制表示法下4和7的数量相等
比如47,474477就是
而4,744,467则不是

现在ztr想知道最小的但不小于n的幸运数字是多少
输入描述
T(1\leq\;T\leq\;10^{5})T(1T105)组数据,每组数据一个正整数nn1\leq\;n\leq\;10^{18}1n1018
输出描述
TT行,每行即答案
输入样例
2
4500
47
输出样例
4747
47
Hint
请尽可能地优化算法,考虑全面
/****************************************************/

出题人的解题思路:

1002.Solution

直接暴力显然TLE,考虑按位DFS

每一位只可能是4或7

所以根据这个来DFS即可,时间复杂度O(T*2^{log_{10}n})O(T2log10n)

考虑到T特别大,不可能每次都DFS

而经过计算,2^{18}=262144218=262144,所以全部储存下来

对于每次询问,二分即可

考虑一个边界条件,即当结果爆ll怎么办?

即答案应当为10个4、10个7的时候,显然unsigned long long也不行

那么只能采用特判了

首先,由于每一位只能是4或7,且
2^{18}=262144
218=262144,故而考虑离线打表,即利用dfs求解出所有只含数字4和7,且4和7数量相等的数
int k1,k2,p;
__int64 ans[N];
void dfs(__int64 sum,int c1,int c2)
{
    if(c1>=k1&&c2>=k2)
    {
        ans[p++]=sum;
        return ;
    }
    if(c1<k1)//4
        dfs(sum*10+4,c1+1,c2);
    if(c2<k2)//7
        dfs(sum*10+7,c1,c2+1);
}
结果存储在ans数组中,此时可以得到符合条件的数有66196+1个,而数据有T组,好吧,那就二分查找
q=lower_bound(ans,ans+p,n)-ans;
需要注意的一点是,当n>777777777444444444的时候,18位数里面已经没有比这更大的符合条件的数了,那么只能特判一下,解为最小的20位符合条件的数,即44444444447777777777
/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100005;
const int M = 40;
const int inf = 100000000;
const int mod = 2009;
int k1,k2,p;
__int64 ans[N];
void dfs(__int64 sum,int c1,int c2)
{
    if(c1>=k1&&c2>=k2)
    {
        ans[p++]=sum;
        return ;
    }
    if(c1<k1)//4
        dfs(sum*10+4,c1+1,c2);
    if(c2<k2)//7
        dfs(sum*10+7,c1,c2+1);
}
int main()
{
    int i,t,q;
    __int64 n;
    p=0;
     for(i=2;i<=18;i+=2)
     {
         k1=k2=i/2;
         dfs(0,0,0);
     }   //printf("p=%d\n",p);
     /*for(i=0;i<p;i++)
         printf("%I64d ",ans[i]);*/
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d",&n);
        q=lower_bound(ans,ans+p,n)-ans;
        //printf("q=%d\n",q);
        if(q<p)
            printf("%I64d\n",ans[q]);
        else
            puts("44444444447777777777");
    }
    return 0;
}
菜鸟成长记

你可能感兴趣的:(ACM,DFS)