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\n", 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结束后不用再排序。

时间: 2024-08-03 23:46:10

hdu 5676 ztr loves lucky numbers的相关文章

hdu 5676 ztr loves lucky numbers(BC——暴力打表+二分查找)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5676 ztr loves lucky numbers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 594    Accepted Submission(s): 257 Problem Description ztr loves luck

hdu 5676 ztr loves lucky numbers(dfs+离线)

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

hdoj ztr loves lucky numbers 5676 (dfs模拟)

ztr loves lucky numbers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 918    Accepted Submission(s): 389 Problem Description ztr loves lucky numbers. Everybody knows that positive integers ar

hdu-5676 ztr loves lucky numbers(乱搞题)

题目链接: 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的幸运数字是多少 输入描述 有TT(1≤T≤10?5??)组数据,

hdu5676 ztr loves lucky numbers DFS

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5676 题意: 定义幸运数为:只存在4和7且4和7数量相等的数,给出n,求比>=n的最小幸运数 思路: 因为n最多18位,幸运数最大是10个4,10个7,这种情况特判掉,爆longlong,其他的暴力搜出所有长度从2-18的幸运数,因为最多9个4,9个7,然后二分找出比这个数大的那个数 代码: 1 #include <bits/stdc++.h> 2 using namespace std;

[HDOJ5676]ztr loves lucky numbers(状压枚举,打表,二分)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5676 题意:输入一个正整数n(n <=10^18),求不小于n的只有4和7组成的数,且4和7数量相同 枚举2~18位偶数位的4.7的组合,01分别代表4或7.存下来后排序,二分查询. trick就是LL存不下20位的数,但是n<=10^18,那么只要特判大于777777777444444444的数都输出44444444447777777777就行了. 1 #include <bits/std

ztr loves lucky numbers(STL)

ztr喜欢幸运数字,他对于幸运数字有两个要求 1:十进制表示法下只包含4.7 2:十进制表示法下4和7的数量相等 比如47,474477就是 而4,744,467则不是 现在ztr想知道最小的但不小于n的幸运数字是多少 输入描述 有T(1≤n≤105)组数据,每组数据一个正整数n(1≤n≤1018) 输出描述 有T行,每行即答案 输入样例 2 4500 47 输出样例 4747 47 Hint 请尽可能地优化算法,考虑全面 LuckNum.h #include <iostream> class

hdu 5677 ztr loves substring 二维费用背包+回文

题目链接: hdu 5677 ztr loves substring 官方题解: //这部分是错的(首先,对于每一个串i跑一次manancher,令g[i][j]=p[j]-1g[i][j]=p[j]−1 这样,g就存储了所有的回文子串的长度 为了方便,把g降到一维表示) 首先,因为字符串长度较小,所以直接二重for循环找就好了,用一个数组 g记录各个回文串的长度 不妨把每一个子串抽象成一个物品 费用为二维的,即{长度,1} 价值是Bool型的 这样就成了一个二维判断可行性费用背包问题 设f(i

HDU 5675 ztr loves math

ztr loves math Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 896    Accepted Submission(s): 347 Problem Description ztr loves research Math.One day,He thought about the "Lower Edition" of