1. 程式人生 > >數位DP總結

數位DP總結

eth while init tmp digits 推斷 logs tdi lcm

a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits.
問一個區間內[l,r]有多少個Beautiful數字
範圍9*10^18

思路一般,但是取模以及映射也是非常玄妙的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
//
dp[i][j][k][sta] means the first i nomber,whether it has limit,the val%2520,the lcm of ezch number ll pow[22],dp[22][2][2520][50]; int num[22],flcm[512],Map[2520],Map1[50],tmp[22],tot; int gcd(int a,int b) { if(!b) return a; return gcd(b,a%b); } int lcm(int a,int b) { if(a==0) return
b; if(b==0) return a; return a*b/gcd(a,b); } void init() { pow[0]=1; for(int i=1;i<=18;i++) { pow[i]=pow[i-1]*10%2520; } for(int i=1;i<(1<<9);i++) for(int j=1;j<=9;j++) if(i&(1<<j-1)) flcm[i]=lcm(flcm[i-(1<<j-1
)],j); for(int i=1;i<=(1<<9);i++) if(!Map[flcm[i]]) Map1[++tot]=flcm[i],Map[flcm[i]]=tot; } ll solve(ll x) { int len=0; ll ans=0; while(x) tmp[++len]=x%10,x/=10; for(int i=1;i<=len;i++) num[i]=tmp[len-i+1]; memset(dp,0,sizeof(dp)); dp[0][1][0][1]=1; for(int i=0;i<=len;i++) for(int j=0;j<2;j++) for(int k=0;k<2520;k++) for(int l=1;l<=tot;l++) { ll p=dp[i][j][k][l]; int pp=Map1[l]; if(!p) continue; if (i==len) { if (k % pp==0) ans+=p; continue; } if(!j) { for(int q=0;q<=9;q++) { dp[i+1][0][(k+q*pow[len-i-1])%2520][Map[lcm(pp,q)]]+=p; } }else { for(int q=0;q<num[i+1];q++) { dp[i+1][0][(k+q*pow[len-i-1])%2520][Map[lcm(pp,q)]]+=p; } dp[i+1][1][(k+num[i+1]*pow[len-i-1])%2520][Map[lcm(pp,num[i+1])]]+=p; } } return ans; } int main() { init(); int cas; scanf("%d",&cas); while(cas--) { ll a,b; scanf("%lld %lld",&a,&b); printf("%lld\n",solve(b)-solve(a-1)); } }
杭州人稱那些傻乎乎粘嗒嗒的人為62(音:laoer)。
杭州交通管理局經常會擴充一些的士車牌照,新近出來一個好消息,以後上牌照,不再含有不吉利的數字了,這樣一來,就可以消除個別的士司機和乘客的心理障礙,更安全地服務大眾。
不吉利的數字為所有含有4或62的號碼。例如:
62315 73418 88914
都屬於不吉利號碼。但是,61152雖然含有6和2,但不是62連號,所以不屬於不吉利數字之列。
你的任務是,對於每次給出的一個牌照區間號,推斷出交管局今次又要實際上給多少輛新的士車上牌照了。

Input輸入的都是整數對n、m(0<n≤m<1000000),如果遇到都是0的整數對,則輸入結束。
Output對於每個整數對,輸出一個不含有不吉利數字的統計個數,該數值占一行位置。
Sample Input

1 100
0 0

Sample Output

80
水體不解釋
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int dp[25][2][2],tmp[25],num[25];
int solve(int x)
{
    int len=0,ans=0;
    while(x) tmp[++len]=x%10,x/=10;
    for(int i=1;i<=len;i++)
        num[len-i+1]=tmp[i];    
    memset(dp,0,sizeof(dp));    
    dp[0][1][0]=1;
    for(int i=0;i<=len;i++)
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
            {
                int pp=dp[i][j][k];
                if(!pp) continue;
                if(i==len)
                    ans+=pp;
                if(!j)
                {
                    if(!k)
                    {
                        for(int q=0;q<=9;q++)
                        if(q!=6&&q!=4) dp[i+1][0][0]+=pp;else if(q!=4)dp[i+1][0][1]+=pp;
                    }else
                    for(int q=0;q<=9;q++)
                    if(q!=6&&q!=2&&q!=4) dp[i+1][0][0]+=pp;else if(q==6) dp[i+1][0][1]+=pp; 
                }else
                {
                    if(!k)
                    {
                        for(int q=0;q<num[i+1];q++)
                        if(q!=6&&q!=4) dp[i+1][0][0]+=pp;else if(q!=4)dp[i+1][0][1]+=pp;
                        
                        if(num[i+1]!=6&&num[i+1]!=4) dp[i+1][1][0]+=pp;else if(num[i+1]!=4)dp[i+1][1][1]+=pp;
                    }else
                    {
                        for(int q=0;q<num[i+1];q++)
                        if(q!=6&&q!=2&&q!=4) dp[i+1][0][0]+=pp;else if(q==6) dp[i+1][0][1]+=pp;
                        if(num[i+1]!=6&&num[i+1]!=2&&num[i+1]!=4) dp[i+1][1][0]+=pp;else if(num[i+1]==6) dp[i+1][1][1]+=pp;
                    }
                }
            }
    return ans;             
}
int main()
{
    int a,b;
    while(~scanf("%d %d",&a,&b)&&(a||b))
    {
        printf("%d\n",solve(b)-solve(a-1));
    }
 } 

數位DP總結