【题目链接】http://acm.hdu.edu.cn/showproblem.php?pid=3652
【解题思路】还记得第一次打这题时和战神改的十分艰辛QAQ。预处理f[i][j][0/1][k]表示长度为i,第i位为j,是否包含13,%13=k的数的个数。统计细节有:已处理位即已确定位如包含13后面可任取。当前处理位>3且前一位确定为1则当前这位取3后后面可任取。注意不要重复计数。
【呆马】
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iostream>
#define ll long long
using namespace std;
int i,j,k,l,x,a[11],f[11][10][2][13];
int cal(ll x,ll y,ll z)
{
for (;y;y--) x*=10;
return (x+z)%13;
}
int go(int x)
{
int i,l=0,t=0;
bool bo=0;
for (i=1;i<=20;i++) a[i]=0;
for (i=0;x;a[++i]=x%10,x/=10);
for (;i;i--)
{
int x=(13-l)%13;
for (int j=0;j<a[i];j++)
{
t+=f[i][j][1][x];
if (bo) t+=f[i][j][0][x];
}
if (!bo && a[i+1]==1 && a[i]>3) t+=f[i][3][0][x];
if (a[i]==3 && a[i+1]==1) bo=1;
l=cal(a[i],i-1,l);
}
return t;
}
int main()
{
for (i=0;i<=9;i++) f[1][i][0][i]=1;
for (i=2;i<=10;i++)
for (j=0;j<=9;j++)
for (k=0;k<=9;k++)
for (l=0;l<13;l++)
{
x=cal(j,i-1,l);
if (j==1 && k==3) f[i][j][1][x]+=f[i-1][k][0][l]+f[i-1][k][1][l];
else f[i][j][0][x]+=f[i-1][k][0][l],f[i][j][1][x]+=f[i-1][k][1][l];
}
for (;scanf("%d\n",&x)==1;) printf("%d\n",go(x+1));
}