BZOJ 1183 Croatian2008 Umnozak

提示:
1. 一个数的Digit-Product能够是什么样的数。
2. 这些数数量有多少呢?

详细题解在代码后:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <algorithm>

using namespace std;
typedef long long ll;
const ll lim = 1000000000000000000LL;
const ll limh = 1000000000;

__inline ll ceil( ll a, ll b ) { return (a+b-1)/b; }
__inline ll floor( ll a, ll b ) { return a/b; }


ll a , b , res = 0;
int k[4];

const int num[]={2,3,5,7};

int dig[10][4];
ll d[20][30][20][20][20];

ll dp(int bit , ll a , ll pos , ll l , ll r)
{
    ll b = a+pos-1;
    if(a>r || b<l) return 0;
    if(bit==18) return !k[0] && !k[1] && !k[2] && !k[3];

// cout<<bit<<" "<<a<<" "<<pos<<" "<<l<<" "<<r<<endl;

    bool memerizeAble = (l<=a && b<=r) ; // Arbitrary process
    ll &now = d[bit][k[0]][k[1]][k[2]][k[3]] , res = 0;

    if(memerizeAble && now>=0) return now;
    pos/=10;

    for(int i=(a!=0);i<10;i++) 
    {
        bool ok = true;
        for(int j=0;j<4;j++) ok &=  k[j]>=dig[i][j];
        if(!ok) continue;

        for(int j=0;j<4;j++) k[j] -= dig[i][j];
        res+= dp(bit+1, a+pos*i, pos, l, r);
        for(int j=0;j<4;j++) k[j] += dig[i][j];
    }
    if(memerizeAble) now = res;
    return res;
}

void dfs(ll now , int d)
{
    if(now>limh || now*now > b)  return;
    if(d==4) 
    {
        res+= dp(0, 0, lim, ceil(a , now), floor(b, now));
        return ;
    }

    dfs(now, d+1);
    k[d]++;
    dfs(now*num[d], d);
    k[d]--;
}

int main(int argc, char *argv[]) {

    memset(d, -1, sizeof(d));
    for(int i=1 , _i=1;i<10;i++ , _i=i) for(int j=0;j<4;j++) while(_i%num[j]==0) _i/=num[j] , dig[i][j]++;

    cin>>a>>b;
    dfs(1, 0);
    cout<<res<<endl;

    return 0;
}

Self-Product只能是2 , 3 , 5 , 7的倍数。 那么其实枚举这些取值是不难做到的。 然后数位DP一下就好。

注意:
由于这里要查询多次 , 所以这里要考虑记录一些通用的答案 , 也就是对于选择没有限制的答案。

你可能感兴趣的:(dp)