1. 程式人生 > >HDU——2089 不要62

HDU——2089 不要62

機房 例如 NPU 優化 服務 pos input 消息 打了

不要62

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 54005 Accepted Submission(s): 20682


Problem Description 杭州人稱那些傻乎乎粘嗒嗒的人為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

Solution:

  話說講了兩星期的數位$DP$了,入坑已久,一直沒去填坑(~妄想著打表出奇跡~

)。

  今天高三二模,學長學姐高考前最後一次模考了,雖然有點喊口號,但我還是想說“高三加油!麓山必勝!”。然後心血來潮,早上$6:30$跑到機房剛數據結構(然而沒剛出),忽覺有坑沒填,於是打了打數位板子題。

  數位$DP$,其實並不難(思路好簡單啊),我們只是換個姿態在打暴力,但套上了記憶化使其大大優化而已。

  普通的模擬水分,一般就是在一段範圍內枚舉每個數,將其每位拆開,然後判斷是否符合條件,計數就$OK$了(但是這樣顯然沒啥規律可循,狀態無法確定,難以記憶化)。

  於是我們換個方式,首先可以利用差分的思想,區間$[l,r]$中滿足條件的數的個數$=$區間$[0,r]$滿足條件的個數$-$區間$[0,l-1]$中滿足條件的個數(這很顯然)。然後我們考慮從高位往低位枚舉$0-9$判斷是否可行,當數位到了$0$位時說明可行,那麽對於$[0,n]$這個區間,每一位都會有個限制$limit$(不能完全枚舉$0-9$中的每一個數)。舉個栗子:$n=345$,枚舉百位時顯然只能從$0-3$中選,然後當百位為$3$時枚舉十位就只能從$0-4$中選(百位為$0,1,2$時,十位就可以從$0-9$枚舉啦)。

  粗略的講下思路,我們定義狀態$f[i][j],i\in[0,8],j=0/1$,表示到了第$i$位,前一位為$j$的方案數($j=0$表示前一位不為$6$,$j=1$表示前一位不為$6$,狀態視題目而定,盡量保證正確性下簡化!),那麽對於所有不受限制的情況都記錄狀態,事實證明優化賊快~。

代碼:

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 4 using namespace std;
 5 int f[20][3],cnt,n,m,ans,p[20];
 6 il int dfs(int pos,int lst,int sta,int limit){
 7     if(!pos)return 1;
 8     if(!limit&&f[pos][sta]!=-1)return f[pos][sta];
 9     int up=limit?p[pos]:9,tmp=0;
10     For(i,0,up)
11         if((lst==6&&i==2)||i==4)continue;
12         else tmp+=dfs(pos-1,i,i==6,limit&&i==p[pos]);
13     if(!limit)f[pos][sta]=tmp;
14     return tmp;
15 }
16 il int solve(int x){
17     cnt=0;
18     while(x){
19         p[++cnt]=x%10;
20         x=x/10;
21     }
22     return dfs(cnt,-1,0,1);
23 }
24 il int gi(){
25     int a=0;char x=getchar();
26     while(x<0||x>9)x=getchar();
27     while(x>=0&&x<=9)a=(a<<3)+(a<<1)+x-48,x=getchar();
28     return a;
29 }
30 int main(){
31     while(1){
32         n=gi(),m=gi();
33         if(!n&&!m)return 0;
34         memset(f,-1,sizeof(f));
35         printf("%d\n",solve(m)-solve(n-1));
36     }
37     return 0;
38 }

HDU——2089 不要62