题意:求1-n(n<=1000000000)的数中,技能被13整除。又包括13子串的数的个数;
解法:数位dp。LL dp[pre][now][have][iflow][rem]记录着第pre位为now,have表示前边是否出现过13,iflow表示dp过程否有减少,rem表示兴许须要的余数是多少。
代码:
/******************************************************
* author:xiefubao
*******************************************************/
//freopen ("in.txt" , "r" , stdin);
using namespace std;
const double pi=acos(-1.0);
typedef long long LL;
const int Max=10100;
const int INF=1000000007;
LL dp[20][20][2][2][15];
int reminder[20];
int num[30];
LL dfs(int pre,int now,bool have,bool iflow,int rem)
{
if(pre==0)
return have&&rem==0;
if(dp[pre][now][have][iflow][rem]!=-1)
return dp[pre][now][have][iflow][rem];
int en=iflow? 9 : num[pre-1];
LL ans=0;
for(int i=0;i<=en;i++)
{
int tool=((rem-(i*reminder[pre-1])%13)+13)%13;
if(now==1&&i==3)
ans+=dfs(pre-1,i,1,iflow||i!=en,tool);
else
ans+=dfs(pre-1,i,have,iflow||i!=en,tool);
}
return dp[pre][now][have][iflow][rem]=ans;
}
void init()
{
reminder[0]=1;
for(int i=1;i<=10;i++)
reminder[i]=(reminder[i-1]*10)%13;
}
LL solve(LL n)
{
int p=0;
memset(dp,-1,sizeof dp);
while(n)
{
num[p++]=n%10;
n/=10;
}
LL ans=0;
for(int i=0;i<=num[p-1];i++)
{
int tool=(i*reminder[p-1])%13;
ans+=dfs(p-1,i,0,i!=num[p-1],(13-tool)%13);
}
return ans;
}
int main()
{
int n;
init();
while(cin>>n)
{
cout<<solve(n)<<'\n';
}
return 0;
}