codeforces 55D Beautiful numbers 數位dp

dp[i][lcm][mod]
i 推到第幾位
lcm 爲 比i高的位的值的最小公倍數,
mod爲此時的數值 %(lcm(1, 2, 3, 4, 5, 6, 7, 8, 9) = 2520)的價值
dp[i][lcm][mod] 的值爲這個狀態時 0 - (i -1)位選擇的方案數使其最後數值%所有位的lcm爲0
因爲2520能夠整除任意由1 - 9 形成的最小公倍數所以%2520 最後判斷 mod % lcm 等於0就合法 不是就不合法
要把1 - 9 形成的所有最小公倍數離散化

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#define LL long long
#define mod 2520
using namespace std;
vector<LL>ve;
LL dp[30][55][2600];
LL has[2000];
LL x[50], l;
LL gcd(LL a, LL b)
{
   while(b)
   {
       int t = a %b;
       a = b;
       b = t;
   }
   return a;
}
LL dfs(int i, bool e, int lcm, LL pre)
{
   if(i == -1)
   {
       if(pre % lcm == 0) return 1;
       else return 0;
   }
   if(e && dp[i][has[lcm]][pre % mod] != -1) return dp[i][has[lcm]][pre % mod];
   LL Max = e ? 9 : x[i], ans = 0;
   for(int j = 0; j <= Max; j++)
       if(j!=0)ans +=  dfs(i - 1, !(!e && j == x[i]), lcm * j / gcd(lcm, j), (pre * 10 + j) % mod);
       else ans += dfs(i - 1, !(!e && j == x[i]), lcm, (pre * 10 + j) % mod);
   if(e) dp[i][has[lcm]][pre] = ans;
   return ans;
}
LL cal(LL n)
{
   l = 0;
   while(n)
   {
      x[l++] = n % 10ll;
      n /= 10ll;
   }
   return dfs(l - 1, 0, 1, 0);
}
void dfs2(int pre,int i)
{
     ve.push_back(pre);
     for(int j = i; j<= 9; j++)
         dfs2(pre * j / gcd(pre, j), j + 1);
}
int main()
{
    dfs2(1,1);
    sort(ve.begin(), ve.end());
    vector<LL>::iterator it = unique(ve.begin(),ve.end());
    ve.erase(it,ve.end());
    for(int i = 0; i < ve.size(); i++) has[ve[i]] = i;
    memset(dp, -1, sizeof(dp));

    LL a, b, t;
    scanf("%I64d", &t);
    while(t--)
    {
        scanf("%I64d %I64d", &a, &b);
        printf("%I64d\n", cal(b) - cal(a - 1));
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章