hdu 3652 "B-number"(数位DP)
参考博文:
[1]:http://www.voidcn.com/article/p-drrnjrmy-wm.html
题意:
找出区间内数中含有13的并且能被13整除的数的个数
题解:
搜了好多博客,看到了一些关键词;
其中一个就有"秦九韶算法",补了补秦九韶算法,再看一下参考博文的代码,感觉,和秦九韶算法关联不是太大;
下面说说我的思路:
假设 num = 121394 ,(num%13=0,且含有"13")
num可写成 1*105+2*104+1*103+3*102+9*101+4;
那么,将这个数任意拆分成两部分,例如 令 a = 1*105+2*104 , b=1*103+3*102+9*101+4;
你会发现 a%13+b%13 = 13;
(假设下标从0开始,最高为为 pos,从第 i 位置断开,[i+1,pos]组成的数为 a)
那么,定义 dp[ i ][ j ][ k ]:
dp[ i ][ j ][0]表示从pos到i+1位不含有"13"且 j = (13-a%13)的数的个数;
dp[ i ][ j ][1]表示从pos到i+1位不含有"13"但是第i+1位是1且 j = (13-a%13)的数的个数 ;
dp[ i ][ j ][2]表示从pos到i+1为含有"13"且 j = (13-a%13) 的数的个数;
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 7 int n; 8 int digit[10]; 9 int dp[10][13][3]; 10 11 int quickPower(int a,int b) 12 { 13 int ans=1; 14 while(b) 15 { 16 if(b&1) 17 ans *= a; 18 a *= a; 19 b >>= 1; 20 } 21 return ans; 22 } 23 //s对应着0,1,2状态 24 int DFS(int curPos,int curNum,int s,bool limit) 25 { 26 if(curPos == -1) 27 return curNum%13 == 0 && s == 2 ? 1:0; 28 29 //以 num = 121394 为例 30 //如果当前的 curPos 来到 3数字处,那么 curNum = 121 31 //而实际要算的是 13-121000%13,所以需要将curNum*1000,就是对应的quickPower() 32 int mod=13-curNum*quickPower(10,curPos+1)%13; 33 if(!limit&&dp[curPos][mod][s] != -1) 34 return dp[curPos][mod][s]; 35 36 int up=limit ? digit[curPos]:9; 37 int ans=0; 38 for(int i=0;i <= up;++i) 39 { 40 int t=0; 41 if(s == 2) 42 t=2; 43 else if(s == 1 && i == 3) 44 t=2; 45 else if(i == 1) 46 t=1; 47 ans += DFS(curPos-1,curNum*10+i,t,limit&&i==digit[curPos]); 48 } 49 if(!limit) 50 dp[curPos][mod][s]=ans; 51 52 return ans; 53 } 54 int Solve(int x) 55 { 56 int k=0; 57 while(x) 58 { 59 digit[k++]=x%10; 60 x /= 10; 61 } 62 return DFS(k-1,0,0,true); 63 } 64 int main() 65 { 66 mem(dp,-1); 67 while(~scanf("%d",&n)) 68 printf("%d\n",Solve(n)); 69 70 return 0; 71 }