1. 程式人生 > 實用技巧 >Beautiful numbers[數位$dp$+狀壓]

Beautiful numbers[數位$dp$+狀壓]

Beautiful numbers[數位\(dp\)+狀壓]

CodeForces - 55D

將0~9數字否存在狀壓到s

再將數字膜上\(1,2,3,4,5,6,7,8,9,\)和20位數放入\(dp\)

這樣空間會有\(9!\times2^{10}\times20\)很明顯會超時。

再往每個膜數上優化。

首先如果一個數x % 8為\(0,2,4,6\)那麼x%2為\(0\)(即\(2\)的倍數)。

膜上2這個可以去除。

一個數x%9為0,3,6,那麼x%3為\(0\)(即\(3\)的倍數)。

膜上3這個可以去除。

一個數x%8為\(0,4\)那麼x%4為\(0\)(即\(4\)的倍數)。

膜上4這個可以去除。

如果一個數x % 8為\(0,2,4,6\)並且x%9為\(0,3,6\)(即既是2的倍數,又是3的倍數),那麼x%6為\(0\)

膜上6這個可以去除。

即可以將膜上\(1,2,3,4,5,6,7,8,9,\)優化為膜上\(5,7,8,9\)

且只需要存上是否存在2~9​的數字(0和1不需要判斷)。

這樣空間會有\(5\times7\times8\times9\times2^8\times20=12,902,400\)勉強能開下。

#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
ll t,l,r,a[20];
ll dp[20][5][7][8][9][307];
ll lin;
ll ksm(ll x,ll p){
    ll res=1;
    while(p){
        if(p%2==1) res=res*x;
        p/=2;
        x=x*x;
    }
    return res;
}
ll dfs(ll p,ll wu,ll qi,ll ba,ll jiu,ll s,ll lim){
    if(p==0){
        ll ok=1;
        for(ll i=0;i<=7;i++){
            if(s&(1<<i)){
                if(i==0){
                    if(!(ba==0||ba==2||ba==4||ba==6)){
                        ok=0;
                    }
                }
                if(i==1){
                    if(!(jiu==0||jiu==3||jiu==6)){
                        ok=0;
                    }
                }
                if(i==2){
                    if(!(ba==0||ba==4)){
                        ok=0;
                    }
                }
                if(i==3){
                    if(wu!=0){
                        ok=0;
                    }
                }
                if(i==4){
                    if(!(ba==0||ba==2||ba==4||ba==6)){
                        ok=0;
                    }
                    if(!(jiu==0||jiu==3||jiu==6)){
                        ok=0;
                    }
                }
                if(i==5){
                    if(qi!=0){
                        ok=0;
                    }
                }
                if(i==6){
                    if(ba!=0){
                        ok=0;
                    }
                }
                if(i==7){
                    if(jiu!=0){
                        ok=0;
                    }
                }
            }
        }
        return ok;
    }
    if(lim==0&&dp[p][wu][qi][ba][jiu][s]!=-1){
        return dp[p][wu][qi][ba][jiu][s];
    }
    ll up=lim? a[p]:9;
    ll ans=0;
    for(ll i=0;i<=up;i++){
        if(i>=2){
            ans+=dfs(p-1,(wu+ksm(10,p-1)*i)%5,(qi+ksm(10,p-1)*i)%7,(ba+ksm(10,p-1)*i)%8
                    ,(jiu+ksm(10,p-1)*i)%9,s|(1<<(i-2)),lim&&i==up);
        }
        else{
            ans+=dfs(p-1,(wu+ksm(10,p-1)*i)%5,(qi+ksm(10,p-1)*i)%7,(ba+ksm(10,p-1)*i)%8
                    ,(jiu+ksm(10,p-1)*i)%9,s,lim&&i==up);
        }
        
    }
    if(lim==0)return dp[p][wu][qi][ba][jiu][s]=ans;
    else return ans;
}


ll solve(ll num){
    ll tot=0;
    while(num){
        a[++tot]=num%10;
        num/=10;
    }
    return dfs(tot,0,0,0,0,0,1);
}

int main(){
    scanf("%lld",&t);
    memset(dp,-1,sizeof(dp));
    while(t--){
        scanf("%lld %lld",&l,&r);
        printf("%lld\n",solve(r)-solve(l-1));
    }
}