数位DP hihocoder1791

  1 /*
  2   题意:求 1...n, n<10^12中满足x%sum(x)==0的数的个数,sum(x)为x的各个位数的和
  3   题解:数位DP
  4   时间:2018.08.03
  5 */
  6 
  7 #include <bits/stdc++.h>
  8 using namespace std;
  9 
 10 typedef long long LL;
 11 const int MAXN = 100005;
 12 const LL MOD7 = 1e9+7;
 13 
 14 LL dp[15][125][125][125];
 15 
 16 // 位数, 和, 模, 余数, dp[i][s][R][r]当前位数是i, 和为s,对R取模余数是r的个数
 17 // 每次枚举最后一位, 有 dp[i+1][s+j][R][(r*10+j)%R] += dp[i][s][R][r];
 18 
 19 void init()
 20 {
 21     memset(dp,0LL,sizeof(dp));
 22     for (int i=1;i<=9*12;++i) dp[0][0][i][0]=1;
 23     for (int i=0;i<=12;++i)
 24     {
 25         for (int s=0;s<=9*12;++s)
 26         {
 27             for (int R=1;R<=9*12;++R)
 28             {
 29                 for (int r=0;r<R;++r)
 30                 {
 31                     if (dp[i][s][R][r])
 32                     {
 33                         for (int j=0;j<=9;++j)
 34                         {
 35                             dp[i+1][s+j][R][(r*10+j)%R]+=dp[i][s][R][r];
 36                         }
 37                     }
 38                 }
 39             }
 40         }
 41     }
 42 }
 43 
 44 int b[15];
 45 int m;
 46 LL n;
 47 
 48 LL get_b(LL n)
 49 {
 50     LL t=1;
 51     m=0;
 52     while (n)
 53     {
 54         b[m++]=n%10;
 55         n/=10;
 56         t*=10;
 57     }
 58     reverse(b,b+m);
 59     return t/10;
 60 }
 61 
 62 
 63 // 统计<n的满足条件的方案数。
 64 // 每次从高位枚举n=a1a2a3...am的一位,例如a2=3 枚举j=0, 1, 2, 3, 然后统计a1固定时,第二位为j时,枚举剩下位置的和为s
 65 //  对应的结果就是就是,长度为 len = m-2, s,
 66 //                      模数 R  = 前面固定的和 + j + s
 67 //                      需要的余数是 r = (R-(前面固定位置的值+ j对应的值) % R) %R
 68 //  也就是 dp[len][s][sum+j+s][(R-(value+j*q)%R)%R] , sum是前面固定位置的总和,value为其对应的值,q=10^len,当前位的权重。
 69 
 70 LL solve(LL n)
 71 {
 72    LL q = get_b(n);
 73    // for (int i=0;i<m;++i) cout<<b[i]<<" ";cout<<endl;
 74    // cout<<q<<endl;
 75    LL ans=0;
 76    int sum=0;
 77    LL value=0;
 78    for (int i=0;i<m;++i)
 79    {
 80        int len= m-i-1;
 81        for (int j=0;j<b[i];++j)
 82        {
 83            for (int s=0;s<=9*len;++s)
 84            {
 85                int R = sum+j+s;
 86                if (R>0)
 87                {
 88                    int r=(int)(R-(value+j*q)%R) % R;
 89                    ans+=dp[len][s][R][r];
 90                }
 91            }
 92        }
 93        value += q*b[i];
 94        q/=10;
 95        sum+=b[i];
 96    }
 97    int tmp=0;
 98    for (int i=0;i<m;++i) tmp+=b[i];
 99    ans+=(n%tmp==0);
100    return ans;
101 }
102 
103 int main()
104 {
105 #ifndef ONLINE_JUDGE
106     // freopen("test.txt","r",stdin);
107 #endif // ONLINE_JUDGE
108     init();
109     scanf("%lld",&n);
110     printf("%lld\n",solve(n));
111     return 0;
112 }

 

posted @ 2018-08-03 18:35  LeeSongt  阅读(149)  评论(0编辑  收藏  举报