描述

定义一个数字 x 是幸运的,当且仅当 x 是 x 十进制下所有数位的和的倍数

例如 1..9 所有数都是幸运数,120 也是幸运数

现在给定 n ,求 [1, n] 中有几个幸运数

输入

第一行一个正整数 n

1 ≤ n ≤ 1012

输出

输出有几个幸运数

样例输入


10


样例输出


10


这道题以前貌似做过,

思路:

如果直接dp,发现dp数组存不下sum,然后因为位数和最大为108,所以就可以枚举所有的位数和,分别跑dp,求解,这样取模后,数组就可以存下了。

注意sum_1 - i <0 剪枝.

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
const int INF=0x3f3f3f3f;
int mod;
ll dp[32][130][120][2];
ll a[30];
ll dfs(int pos,ll sum_1,ll sum_2,int limit)
{
if(pos==-1){return (sum_1==0)&&(sum_2==0);}
if(!limit&&dp[pos][sum_1][sum_2][limit]!=-1)return dp[pos][sum_1][sum_2][limit];
ll ans=0;
int end=limit?a[pos]:9;
for(int i=0;i<=end;i++)
{
if(sum_1-i<0)break;
ans+=dfs(pos-1,sum_1-i,(sum_2*10+i)%mod,limit&&(i==a[pos]));
}
if(!limit)dp[pos][sum_1][sum_2][limit]=ans;
return ans;
}

ll go(ll x)
{
int pos=0;
while(x)
{
a[pos++]=x%10;
x/=10;
}
ll ans=0;
for(int i=1;i<=pos*9;i++)
{
memset(dp,-1,sizeof(dp));
mod=i;
ans+=dfs(pos-1,i,0,1);
}
return ans;
}
int main()
{
ll n;
memset(dp,-1,sizeof(dp));
scanf("%lld",&n);
cout<<go(n)<<endl;
return 0;
}