數位DP——HDU 3555 要49
阿新 • • 發佈:2019-02-14
題目連結:
題目大意:
給定一個數n,求取1-n這個閉區間中包含49的數字的個數。(n小於2的64次方)
解題思路:
由於這個題目的範圍比較大,所以採用暴力肯定會超時,而且不能開除這麼大的陣列。
比較基礎的數位DP。
定義了3種狀態:
dp[i][0]:i位數字的時候不包含49的數字個數
dp[i][1]:i位數字的時候不包含49並且最高位是9的數字個數
dp[i][2]:i位數字的時候包含49的數字個數
原始碼:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<set> #include<map> #include<vector> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; int date[25]; __int64 dp[25][3]; //狀態0表示不包含49 //狀態1表示不包含49並且最高位是9 //狀態2表示包含49 void init() //預處理dp陣列,注意這個陣列開大點,到25左右,不然會wa { int i; memset(dp,0,sizeof(dp)); dp[0][0]=1; for(i=1;i<=25;i++) { dp[i][0]=dp[i-1][0]*10-dp[i-1][1]; dp[i][1]=dp[i-1][0]; dp[i][2]=dp[i-1][2]*10+dp[i-1][1]; } return; } __int64 DP(__int64 x) { __int64 ans,sum,flag; int len,i; ans=len=flag=0; while(x) { date[++len]=x%10; x/=10; } date[len+1]=0; for(i=len;i>=1;i--) { ans+=dp[i-1][2]*date[i]; //後面出現了49,當前位可以取0-date[i]-1 if(flag) ans+=dp[i-1][0]*date[i]; //前面出現了49,當前位可以去0-date[i]-1 else { if(date[i]>4) ans+=dp[i-1][1]; //當前位取4,下一位取9 } if(date[i]==9 && date[i+1]==4) flag=1; } return ans; } int main() { //freopen("in.txt","r",stdin); int cs; __int64 n; init(); scanf("%d",&cs); while(cs--) { scanf("%I64d",&n); printf("%I64d\n",DP(n+1)); } return 0; }