您的位置:首页 > 其它

【HDU 3652】B-number

2016-05-07 08:49 253 查看
B-number

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 4096 Accepted Submission(s): 2335

Problem Description

A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string “13” and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task is to calculate how many wqb-numbers from 1 to n for a given integer n.

Input

Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).

Output

Print each answer in a single line.

Sample Input

13

100

200

1000

Sample Output

1

1

2

2

[题意][计算在1-n中各位上的数字之和是13的倍数且含有13的数的个数]

【题解】【数位dp】

【f[i][j][k]:代表i位数开头为j.k=0代表含有‘13’的情况; k=1代表不含‘13’且首位不为3的情况; k=2代表不含‘13’且首位为3的情况】

【依据 a%13+b%13=j==(a+b)%13转移】

【这其实是数位dp较为经典的写法】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll f[20][20][3],h[20],tot,mi[20];
ll n;
inline void dp()
{
f[0][0][1]=1;
int i,j,k;
for(i=0;i<10;++i)
{
f[1][i%13][0]=0;
if(i!=3) f[1][i%13][1]=1;
if(i==3) f[1][i%13][2]=1;
}
int a,amod,bmod;
for(k=2;k<=10;++k)//枚举位数
for(i=0;i<13;++i)//枚举余数
for(j=0;j<10;++j)//枚举当前位可能出现的数字
{
a=j*mi[k-1]; amod=a%13;
bmod=((i-amod)%13+13)%13;//a%13+b%13=j==(a+b)%13

f[k][i][0]+=f[k-1][bmod][0];//继承
if(j==1) f[k][i][0]+=f[k-1][bmod][2];//若当前位是1,则继承上一位是3的情况
if(j!=3)//当前不需要更新f[i][j][2]
{
f[k][i][1]+=f[k-1][bmod][1];//继承
if(j!=1) f[k][i][1]+=f[k-1][bmod][2];//如果当前为不是1,则依旧不含13,所以继承上一位是3的情况
}
if(j==3) f[k][i][2]+=f[k-1][bmod][2]+f[k-1][bmod][1];//如果当前位是3,则继承前面所有不含13的情况
}
}

inline ll math(ll n)
{
memset(h,0,sizeof(h)); tot=0;
while(n) h[++tot]=n%10,n/=10;
ll ans=0,amod=0,bmod=0,last=0,a=0;
ll i,j;
bool t=false;
for(i=tot;i>0;--i)
{
for(j=0;j<h[i];++j)
{
a=last+mi[i-1]*j;
amod=a%13;
bmod=((0-amod)%13+13)%13;
ans+=f[i-1][bmod][0];
}//加上以上一位为开头并且含有13的情况
if(t)
{
for(j=0;j<h[i];++j)
{
a=last+mi[i-1]*j;
amod=a%13;
bmod=((0-amod)%13+13)%13;
ans+=f[i-1][bmod][1]+f[i-1][bmod][2];
}
last+=h[i]*mi[i-1];
continue;
}//如果前一位是3,当前位是1
if(h[i+1]==1&&h[i]>3)//如果上一位是1,且当前位可以取到3,所以加上当前位是3且不含13的情况
{
a=last;
amod=a%13;
bmod=((0-amod)%13+13)%13;
ans+=f[i][bmod][2];
}
if(h[i]>1)//当前位某>1,说明可以出现13,即前一位可以是3
{
a=last+mi[i-1];
amod=a%13;
bmod=((0-amod)%13+13)%13;
ans+=f[i-1][bmod][2];
}
if(h[i]==3&&h[i+1]==1) t=true;
last+=h[i]*mi[i-1];
}
return ans;
}
int main()
{
mi[0]=1;
for(int i=1;i<=10;++i) mi[i]=mi[i-1]*10;
dp();
while(scanf("%I64d",&n)!=EOF)
printf("%I64d\n",math(n+1));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: