1. 程式人生 > >CF D. Beautiful numbers (數位dp)

CF D. Beautiful numbers (數位dp)

推斷 force __int64 mes res com snippet csdn display

http://codeforces.com/problemset/problem/55/D


Beautiful Numbers : 這個數能整除它的全部位上非零整數。問[l,r]之間的Beautiful Numbers的個數。


若一個數能整除它的全部的非零數位。那麽相當於它能整除個位數的最小公倍數。

因此記憶化搜索中的參數除了len(當前位)和up(是否達到上界),有一個prelcm表示前面的數的最小公倍數。推斷這個數是否是Beautiful Numbers,還要有一個參數表示前面數,可是這個數太大,須要縮小它的範圍。


難點:

縮小前面組成的數的範圍。

能夠發現全部個位數的最小公倍數是2520,如果當前的Beautiful Numbers是x,

那麽 x % lcm{dig[i]} = 0,

又 2520%lcm{dig[i]} = 0,

那麽x%2520%lcm{ dig[i] } = 0,x範圍由9*10^18變為2520。



處理超內存問題。

經過分析後能夠設出dp[20][2050][2050],dp[i][j][k]表示處理到i位,前面的數的最小公倍數為j。前面的數%2520為k。

但這樣

明顯會TLE。。

由於1~9組成的最小公倍數僅僅有48個,能夠離散化,這樣數組就降到了dp[20][50][2520]。







#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
//#define LL __int64
#define LL long long
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 4010;
const int max_lcm = 2520;

LL gcd(LL a, LL b)
{
    if(b == 0)
        return a;
    return gcd(b,a%b);
}
LL lcm(LL a, LL b)
{
    return a/gcd(a,b)*b;
}
int dig[25];
LL dp[25][50][2525];
int hash[2525];

LL dfs(int len, int prelcm, int prenum, int up)
{
    if(len == 0)
    {
        return prenum%prelcm == 0;
    }
    if(!up && dp[len][hash[prelcm]][prenum] != -1)
        return dp[len][hash[prelcm]][prenum];
    int n = up ?

dig[len] : 9; LL res = 0; for(int i = 0; i <= n; i++) { int nownum = (prenum*10+i)%max_lcm; int nowlcm = prelcm; if(i) nowlcm = lcm(prelcm,i); res += dfs(len-1,nowlcm,nownum,up&&i==n); } if(!up) dp[len][hash[prelcm]][prenum] = res; return res; } LL cal(LL num) { int len = 0; while(num) { dig[++len] = num%10; num /= 10; } return dfs(len,1,0,1); } int main() { int test; LL a,b; int cnt = 0; for(int i = 1; i <= 2520; i++) //離散化 { if(max_lcm % i == 0) hash[i] = ++cnt; } scanf("%d",&test); memset(dp,-1,sizeof(dp)); for(int item = 1; item <= test; item++) { scanf("%I64d %I64d",&a,&b); printf("%I64d\n",cal(b) - cal(a-1)); } return 0; }




CF D. Beautiful numbers (數位dp)