HDU 2089 - No 62 or 4


http://acm.hdu.edu.cn/showproblem.php?pid=2089
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。

Input
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。

Output
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。

Sample Input
1 100 0 0

Sample Output
80
https://blog.csdn.net/wust_zzwh/article/details/52100392
入门题。就是数位上不能有4也不能有连续的62,没有4的话在枚举的时候判断一下,不枚举4就可以保证状态合法了,所以这个约束没有记忆化的必要,而对于62的话,涉及到两位,当前一位是6或者不是6这两种不同情况我计数是不相同的,所以要用状态来记录不同的方案数。
dp[pos][sta]表示当前第pos位,前一位是否是6的状态,这里sta只需要去0和1两种状态就可以了,不是6的情况可视为同种,不会影响计数。

typedef long long ll;
int a[20];
int dp[20][2];
int dfs(int pos,int pre,int sta,bool limit)
{
    if(pos==-1) return 1;
    if(!limit && dp[pos][sta]!=-1) return dp[pos][sta];
    int up=limit ? a[pos] : 9;
    int tmp=0;
    for(int i=0;i<=up;i++)
    {
        if(pre==6 && i==2)continue;
        if(i==4) continue;//都是保证枚举合法性
        tmp+=dfs(pos-1,i,i==6,limit && i==a[pos]);
    }
    if(!limit) dp[pos][sta]=tmp;
    return tmp;
}
int solve(int x)
{
    int pos=0;
    while(x)
    {
        a[pos++]=x%10;
        x/=10;
    }
    return dfs(pos-1,-1,0,true);
}
int main()
{
    int le,ri;
    //memset(dp,-1,sizeof dp);可优化
    while(~scanf("%d%d",&le,&ri) && le+ri)
    {
        memset(dp,-1,sizeof dp);
        printf("%d\n",solve(ri)-solve(le-1));
    }
    return 0;
}

http://www.calvinneo.com/2017/09/23/HDU2089%E4%B8%8D%E8%A6%8162/
这条题目是典型的求[L, R]区间内满足某性质的整数的数目问题,通常解法是用[0, R]区间的数目减去[0, L-1]区间的数目。数位DP是此类问题常见的解题思路。
数位dp其实类似于中记忆化搜索。数位DP由最深NNR的十进制位数)层dfs组成。出于实现方便,数字123映射到int nums[]数组中,首尾颠倒变成[3,2,1]。由于从原数字的最高位往最末位递归,因此记忆化搜索的每次递归pos是从N1递减的。

1
2
3
4
5
6
7
8
9
10
11
12
LL solve(int x){
 memset(nums, 0, sizeof nums);
 memset(dp, -1, sizeof dp);
 int ppos = 0;
 while (x != 0) {
  nums[ppos++] = x % 10;
  x /= 10;
 }
 // 开始dfs记忆化搜索
 LL ans = dfs(ppos - 1, 0, true);
 return ans;
}

flag表示在遍历当前pos位时,比pos位低的[0..pos1]位是否有限制,其初始值为true,因为最高位肯定是有限制的。例如数字234,在遍历到cur[2]1时,cur[2..1]能够取遍[10..19],但是当cur[2]为能取的上确界2时,低位的cur[1]只能够在[0..nums[1]]的范围里面取了,cur[2..1]取值为[21..23]。总结规律,只有前缀[pos+1..N1]flagtrue(前缀的所有位都取到了上确界),当前位pos的当前值cur[pos]也取上确界nums[pos]9时,低位cur[pos1]只能取[0..nums[pos1]],否则能自由取[0..9]status用来表示状态,这个状态被用来计算当前子问题的结果,例如在这道题目中,status用来记录是否存在62或者4。
子结构一般为dp[pos][..]..的多维数组。后面的几维与状态有关,有时候可能还需要进行离散化。从上面可知当flagtrue的时候,不能取满[0..9],此时我们就没必要记录下结果,因为显然取满的情况是占绝大多数的。因此dfs的结构如下



LL dfs(int pos, int status, bool flag) {
 if (pos == -1) {
  // 如果到达最深层,check是否继续满足题目中的性质
  return check(status) ? 1 : 0;
 }
 if (!flag && dp[pos][status] != -1) {
  // 如果此层能够取满,那查看能不能复用存储的结果
  return dp[pos][status];
 }
 LL ans = 0;
 int end = flag ? nums[pos] : 9; // 如果flag为true就是不自由的,end只能取到nums[pos]
 for (int i = 0; i <= end; i++)
 {
  int newstatus = ...;
  // 如果最终结果与前缀的结果满足and或者or的性质,这里还可以剪枝
  bool newflag = flag && (i == end); // 下一层的flag,注意要满足两个条件
  ans += dfs(pos - 1, newstatus, newflag);
 }
 if (!flag)
 {
  // 只保存任何层取满[0..9]的结果
  dp[pos][status] = ans;
 }
 return ans;
}

https://111qqz.com/2016/03/hdu-2089/
https://gukaifeng.me/?p=368


¨对于一个小于n的数,肯定是从高位到低位出现某一位<n的那一位。
¨如 n = 58 n为十进制数。
¨  x = 49 此时x的十位<n
¨  x = 51 此时x的个位<n
¨有了上述性质,我们就可以从高到低枚举第一次<n对应位是哪一位。
这样之前的位确定了,之后的位就不受n的限制即从00…0~99…9,可以先预处理
using namespace std;
const double eps = 1E-8;
const int dx4[4]={1,0,0,-1};
const int dy4[4]={0,-1,1,0};
const int inf = 0x3f3f3f3f;
int n,m;
int dp[30][2];
int digit[30];
int dfs (int pos,bool preis6,bool limit)  //pos表示从低到高的第几位,是从高位往低位递归的(也就是从左到又)
                                          // preis6 表示上一个数字是否为6,
                                          // limit表示该位置是否有限制。
{
//    cout<<pos<<" "<<preis6<<" "<<limit<<" "<<endl;
    if (pos==0) return 1; //到该位置表明找到了一个解.
    int res = 0 ;
    if (!limit&&dp[pos][preis6]!=-1) return dp[pos][preis6];  //如果不是limit位置,表示结果是通用的,而之前又算过的话,就可以直接调用这个结果。
    int mx = limit?digit[pos]:9; //mx第pos位置能取到的最大的数字..如果不是limit,则可以0..9任意取。
//    cout<<"mx:"<<mx<<endl;
    
    for ( int i = 0 ; i <= mx;  i++)
    {
        if (i==4||(i==2&&preis6)) continue;
        res += dfs(pos-1,i==6,limit&&i==mx);
        //(limit&&i==mx)中limit的含义是。。如果当前一位不是limit位(即0..9可以随便取的位置)
        //,那么之后的位置也一定不是limit位置。
        //而i==mx部分的意思是,在当前位置的数字小于当前位置的数字能取的最大值(mx)之前,
        //后面位的数字随便取也不会超过上界。
    }
    
    if (!limit) dp[pos][preis6]=res;  //记忆化. 非limit位的结果才通用,不然没必要存。
    return res;
}
int solve ( int n)
{
    ms(digit,0);  //将数按照每一位存到digit数组中
    int len = 0 ;
    while (n)
    {
        digit[++len] = n % 10;
        n/=10;
    }
    return dfs(len,false,true);
}
int main()
{
        #ifndef  ONLINE_JUDGE
        freopen("code/in.txt","r",stdin);
  #endif
        while (~scanf("%d %d",&n,&m))
        {
            if (n==0&&m==0) break;
            
            ms(dp,-1);
            int ans = solve (m)-solve(n-1);
            printf("%d\n",ans);
        }
  #ifndef ONLINE_JUDGE  
  fclose(stdin);
  #endif
    return 0;
}

https://yunhao.space/2018/06/17/acm-hdu-2089-digital-dp/

int n, m;
int s[10];
int len;
int dp[10][2];

int dfs(int pos, int lim, int prev){
    if(pos < 0) return 1;
    if(lim == -1 && dp[pos][prev == 6] != 0) return dp[pos][prev == 6];

    int up = lim==-1?9:lim;

    int tmp = 0;
    for(int i = 0; i <= up; i++){
        if(i == 4) continue;
        if(i == 2 && prev == 6) continue;
        if(i == lim)
            tmp += dfs(pos-1, s[pos-1], i);
        else
            tmp += dfs(pos-1, -1, i);
    }

    if(lim == -1){
        dp[pos][prev == 6] = tmp;
    }

    return tmp;
}

int solve(int num){
    len = 0;
    memset(s, 0, sizeof s);

    while(num > 0){
        s[len++] = num % 10;
        num /= 10;
    }

    return dfs(len-1, s[len-1], -1);
}

int main(){
    while(~scanf("%d %d", &n, &m)){
        if(n == 0 && m == 0) break;
        memset(dp, 0, sizeof dp);

        printf("%d\n", solve(m)-solve(n-1));
    }
    return 0;
}
https://blog.csdn.net/wust_zzwh/article/details/52100392
就是数位上不能有4也不能有连续的62,没有4的话在枚举的时候判断一下,不枚举4就可以保证状态合法了,所以这个约束没有记忆化的必要,而对于62的话,涉及到两位,当前一位是6或者不是6这两种不同情况我计数是不相同的,所以要用状态来记录不同的方案数。
dp[pos][sta]表示当前第pos位,前一位是否是6的状态,这里sta只需要去0和1两种状态就可以了,不是6的情况可视为同种,不会影响计数。


dp[len][0 / 1] 表示不含 4 和 62的前提下,剩余长度为 len ,首位是否为 6 的个数。
思路大概是依次把每位作为最高位,枚举这位可取的数字,决定后面需要的状态,相加,都不需要照着转移方程写了。
X.
https://www.cnblogs.com/alihenaixiao/p/4917631.html
  用数位dp做这个题目的时候,首先要预处理出dp[x][y],代表以y开头的x位数中不含有62和4的数有多少个,在满足条件的情况下状态转移为:dp[x][y] += dp[x-1][k]。又因为对于一个数字x,如果和它位数相同的数字y小于x,那么只需要y数字其中任意一位小于x即可。然后问题就变为求ans([1, r+1]) - ans([1, l])。
12 void init ()
13 {
14     memset(dp, 0, sizeof(dp));
15     dp[0][0] = 1;
16     for (int i=1; i<=7; i++)//i位数
17         for (int j=0; j<10; j++)//第i位数
18             for (int k=0; k<10; k++)//第i-1位数
19             {
20                 if(j==4 || j==6&&k==2)
21                     continue ;
22                 dp[i][j] += dp[i-1][k];
23             }
24 }
25 
26 int solve (int n)
27 {
28     int a[maxn], len = 0, ans = 0;
29     while (n)
30     {
31         a[++len] = n % 10;
32         n /= 10;
33     }
34     a[len+1] = 0;
35 
36     for (int i=len; i>0; i--)
37     {//枚举后len位的策略
38         for (int j=0; j<a[i]; j++)
39         {
40             if (j==4 || a[i+1]==6&&j==2)
41                 continue ;
42             ans += dp[i][j];
43         }
44 
45         if (a[i]==4 || a[i+1]==6 && a[i]==2)
46             break;
47     }
48     return ans;
49 }
50 
51 int main ()
52 {
53     int n, m;
54     init ();
55 
56     while (scanf ("%d %d", &n, &m), n + m)
57         printf ("%d\n", solve(m+1) - solve(n));
58     return 0;
59 }



Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts