B-number HDU - 3652
原题链接
考察:数位dp
思路:
只从看了那道CF55D题我数位dp越写越懵(.)
这道题用容斥原理写的,有正常的循环写法: GO
要注意求的数不同,最后判断条件也不同.
Code
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 13;
int f[N][N][N],n;
LL pows[N];
int get(LL n)
{
return (n%13+13)%13;
}
void init()
{
for(int i=0;i<10;i++) f[1][i][i] = 1;
pows[0] = 1;
for(int i=1;i<N;i++) pows[i] = pows[i-1]*10;
for(int i=2;i<N;i++)
for(int j=0;j<10;j++)
for(int k=0;k<10;k++)
{
if(j==1&&k==3) continue;
for(int s=0;s<13;s++)
f[i][j][s]+=f[i-1][k][get(s-j*pows[i-1])];
}
}
LL dp(int n,bool ok)//不包含13
{
if(!n) return 1;
vector<int> v;
while(n) v.push_back(n%10),n/=10;
LL res = 0; int last =0;int now = 0;
for(int i=v.size()-1;i>=0;i--)
{
int x = v[i];
for(int j=0;j<x;j++)
for(int k=0;k<13;k++)
{
if(last==1&&j==3) break;
if(ok)
res+=f[i+1][j][k];
else
if((k+now%13*pows[i+1]%13)%13!=0)
res+=f[i+1][j][k];
}
if(x==3&&last==1) break;
last = x;
now = x+now*10;
if(!i)
{
if(ok) res++;
else if(now%13!=0) res++;
}
}
return res;
}
int main()
{
init();
while(scanf("%d",&n)!=EOF)
{
int a = n-n/13;//不是13倍数的数
int b = dp(n,1)-1;//不包含13的数
int c = dp(n,0);//不包含13且不能被13整除的数.
LL res = (LL)a+b-c;
printf("%lld\n",n-res);
}
return 0;
}