题目:http://acm.hdu.edu.cn/showproblem.php?pid=3652
分析:
数位DP
f[i][j][k]表示 长i位、j开头、余k,且含13的方案数
g[i][j][k]表示长i位、j开头、余k,且不含13的方案数
f可由f和g转移而来
g只能由g转移而来
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
ll f[20][20][20],g[20][20][20];//i位 j开头 余k
//含13 g不含13
ll ten[15],mod,ans;
int n,len,num;
int main()
{
int i,j,k,h;
ten[0]=1;
for(i=1;i<=10;i++)
ten[i]=ten[i-1]*10;
for(i=0;i<=9;i++)
g[1][i][i]=1;
for(i=2;i<=10;i++)
for(j=0;j<=9;j++)
for(k=0;k<13;k++)
{
mod=(k+13-j*ten[i-1]%13)%13;
for(h=0;h<=9;h++)
f[i][j][k]+=f[i-1][h][mod];
if(j==1) f[i][j][k]+=g[i-1][3][mod];
for(h=0;h<=9;h++)
g[i][j][k]+=g[i-1][h][mod];
if(j==1) g[i][j][k]-=g[i-1][3][mod];
}
while(scanf("%d",&n)==1)
{
ans=0;
mod=0;
for(i=1;i<=10;i++)
if(n/ten[i]==0) break;
len=i;
bool ok=false;
for(i=len;i>=1;i--)
{
num=n/ten[i-1]%10;
for(j=0;j<num;j++)
ans+=f[i][j][(13-mod)%13];
if(ok==true)
{
for(j=0;j<num;j++)
ans+=g[i][j][(13-mod)%13];
}
else if(n/ten[i]%10==1&&num>3)
ans+=g[i][3][(13-mod)%13];
if(num==3&&((n/ten[i]%10)==1)) ok=true;
mod=(mod+num*ten[i-1]%13)%13;
}
if(ok==true&&n%13==0) ans++;
cout<<ans<<endl;
}
return 0;
}