题目:
http://acm.hdu.edu.cn/showproblem.php?pid=3555
学习下如此高端的DP;
//dp[i][j]表示计算到第i位时,状态为j的数的个数 //j=0表示之前不含49且前一位不是4,j=1表示之前不含49但前一位是4,j=2表示之前已经包含49
//dfs函数:pos为当前所处的位,have记录状态(即dp数组的第二维),doing表示前一位是否达到了其最大值,若达到则后面的一位的上限会有限制
#include<cstdio>
#include<algorithm>
using namespace std;
__int64 dp[20][3];
int digit[20];
__int64 dfs(int pos , int have , bool doing)
{
if(pos == -1)
return have == 2;
if(!doing && dp[pos][have] !=-1)
return dp[pos][have];
__int64 ans = 0;
int end = doing ? digit[pos] : 9;
for(int i = 0 ; i <= end; i++)
{
int nhave = have;
if(have == 1 && i != 4)
nhave = 0;
if(have == 0 && i == 4)
nhave = 1;
if(have == 1 && i == 9)
nhave = 2;
ans += dfs(pos-1 , nhave , doing && i == end);
}
if(!doing)
{
dp[pos][have] = ans;
}
return ans;
}
__int64 cal(__int64 x)
{
int pos = 0;
while(x)
{
digit[pos++] = x % 10;
x /= 10;
}
return dfs(pos - 1 , 0 , 1);
}
int main()
{
memset(dp,-1,sizeof(dp));
int T;
for(scanf("%d",&T) ; T-- ;)
{
__int64 n;
scanf("%I64d",&n);
printf("%I64d\n",cal(n));
}
return 0;
}
求[1,n]内有多少个数字,该数字有13,且能被13整除 n<=10^9
x % 13 = 0
(pre*10^pos + next) % 13 = 0 pre是之前确定的部分
需要的参数为pre , pos , 状态have
have记录pre拥有"13",pos+1位为"1",没有"13" 分别用have = 2,1,0表示
然后记忆化搜索
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[10][13][3];
int digit[10];
__int64 dfs(int pos , int pre , int have , bool doing)
{
if(pos == -1)
return have == 2 && pre == 0;
if(!doing && dp[pos][pre][have] != -1)
return dp[pos][pre][have];
int ans = 0;
int end = doing ? digit[pos] : 9;
for(int i = 0 ; i <= end ; i ++)
{
int npre = (pre*10 + i) % 13;
int nhave = have;
if(have == 0 && i == 1)
nhave = 1;
else if(have == 1 && i != 1)
nhave = 0;
if(have == 1 && i == 3)
nhave = 2;
ans += dfs(pos-1 , npre , nhave , doing && i == end );
}
if(!doing)
dp[pos][pre][have] = ans;
return ans;
}
int cal(int x)
{
int pos = 0;
while(x)
{
digit[pos++] = x % 10;
x /= 10;
}
return dfs(pos - 1 , 0 , 0 , 1);
}
int main()
{
memset(dp,-1,sizeof(dp));
int n;
while(~scanf("%d",&n))
printf("%d\n",cal(n));
return 0;
}