zoukankan      html  css  js  c++  java
  • hdu 5676 ztr loves lucky numbers

      题目链接:hdu 5676

      一开始看题还以为和数位dp相关的,后来才发现是搜索题,我手算了下,所有的super lucky number(也就是只含数字4, 7且4, 7的数量相等的数)加起来也不过几万个,可以采用打表的方法来把所有的super lucky number存储起来。因为4,7数量须相等,所以可以用一个二进制数的0,1来代替,先限定4,7数量分别为 i,之后就是求出包含 i 个0和 i 个1的 2*i 位所有这样的二进制数,然后简单转换一下(1->7, 0->4,这样子能从小到大 push 进 vector 中)得到对应的4,7数量分别为 i 的super lucky number,i 从1枚举到9(因为9*2=18达到了long long的上限)就能得到所有的super lucky number了,打好表后剩下的便是二分查找了。一开始wa了一发,后来才知道需要特判,因为打的表中最大的数只达到777777777444444444(9个4,9个7),对于比这个更大的数可以直接知道是44444444447777777777(10个4,10个7)。

    代码如下:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    typedef unsigned long long ull;
    #define  For(i,s,t)  for(int i = s; i != t; ++i)
    
    vector<ull> luckys;
    ull p10[20] = {1, 10, };
    
    // 对于二进制数 x 做一个简单的转换
    inline ull trans(int x, int m) {
        ull num = 0;
        For(j, 0, m)
            num += ((x & (1 << j)) ? 7 : 4) * p10[j];
        return num;
    }
    
    // 求所有含有num1个1和num1个0的2*num1位的二进制数
    template <typename T>
    inline void cal(int num1, vector<T> &vec) {
        int Max = 0, high = num1 << 1;
        For(j, num1, high)  Max |= (1 << j);
        int st = 0;
        For(j, 0, num1)   st |= (1 << j);
        while(st <= Max) {
            vec.push_back(trans(st, high));
            int x = st & -st, y = st + x;          // 这个是《挑战》书上的模板,从小到大枚举二进制数中含有固定数量'1'的所有数
            st = ((st & ~y) / x >> 1) | y;
        }
    }
    
    inline void init(int n = 9) {
        For(i, 1, 19)
            p10[i] = p10[i - 1] * 10;
        For(i, 1, n + 1)
            cal(i, luckys);
    }
    
    // 模板函数二分查找vec中大于等于x的第一个元素
    template <typename T>
    inline int _find(const vector<T> &vec, const T &x) {
        int mid, low = 0, up = vec.size() - 1;
        while(low <= up) {
            mid = low + ((up - low) >> 1);
            if(x < vec[mid] || !(vec[mid] < x))    up = mid - 1;
            else    low = mid + 1;
        }
        return low;
    }
    
    int main() {
        init();
        int t;
        ull n;
        scanf("%d", &t);
        while(t--) {
            scanf("%llu", &n);
            if(n > 777777777444444444)   puts("44444444447777777777");      // 需要特判
            else {
                int id = _find(luckys, n);
                printf("%llu
    ", luckys[id]);
            }
        }
        return 0;
    }

      后来在网上看了下,发现还能直接深搜打表的,简单又清晰多了:

    void dfs(ull sum, int num4, int num7) {
        if(num4 == 0 && num7 == 0) {
            luckys.push_back(sum);
            return ;
        }
        if(num4)    dfs(sum * 10 + 4, num4 - 1, num7);
        if(num7)    dfs(sum * 10 + 7, num4, num7 - 1);
    }
    
    inline void init() {
        For(i, 1, 10)
            dfs(0, i, i);
    }

      得到的同样是从小到大的顺序,dfs结束后不用再排序。

  • 相关阅读:
    windows下安装redis以及redis扩展,设置redis为windows自启服务
    Redis和Memcache的区别
    Git 简单入门使用
    ssh 连接 mac osx下 virtual box虚拟机中的 cent os 记录
    把可运行jar转换成Linux服务运行
    CentOS 7 配置FTP(vsftpd)
    团队总结
    第五周小组项目总结
    第四周小组项目总结
    第三周小组项目总结
  • 原文地址:https://www.cnblogs.com/Newdawn/p/5479508.html
Copyright © 2011-2022 走看看