[kuangbin带你飞]专题十五 数位DP(Except I K)

(难度C-D-E-G-H-A-F-B-J)
数位dp整体思路就是确立状态开始dfs
注意
大部分情况memset -1 比较快
大部分情况memset只执行1次
digit这一维大部分情况下可以省掉

A-cf55D

题解:

题意大致是求 [ l , r ] [l,r] [l,r]区间内各个位上的数都是其因子的个数。

考虑 d p [ l e n ] [ d i g i t ] [ p r e ] [ n u m 2 ] [ n u m 3 ] [ n u m 5 ] [ n u m 7 ] dp[len][digit][pre][num2][num3][num5][num7] dp[len][digit][pre][num2][num3][num5][num7]

p r e pre pre记录其值 m o d ( 8 ∗ 9 ∗ 5 ∗ 7 ) mod(8*9*5*7) mod8957的值, n u m 2 num2 num2代表因子 2 2 2的个数, n u m 3 num3 num3代表因子 3 3 3的个数……

在len==1是我们只要看pre这个数是否符合有后四维的情况即可

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}

ll dp[20][10][2530][4][3][2][2],num[21];
ll dfs(int len,int digit,bool up,int pre,int num_2,int num_3,int num_5,int num_7){
    if(len==1){
        int tmp=1;
        //cout<<pre<<' ';
        for(int i=1;i<=num_2;i++) tmp*=2;
        for(int i=1;i<=num_3;i++) tmp*=3;
        for(int i=1;i<=num_5;i++) tmp*=5;
        for(int i=1;i<=num_7;i++) tmp*=7;
        //cout<<tmp<<endl;
        if(pre%tmp==0) return 1;
        else return 0;
    }
    if(dp[len][digit][pre][num_2][num_3][num_5][num_7]!=-1&&!up) return dp[len][digit][pre][num_2][num_3][num_5][num_7];
    ll res=0;
    int num2=num_2,num3=num_3,num5=num_5,num7=num_7;
    for(int i=0;i<=(up?num[len-1]:9);i++){
        if(i==2) num_2=max(1,num_2);
        else if(i==3) num_3=max(1,num_3);
        else if(i==4) num_2=max(2,num_2);
        else if(i==5) num_5=1;
        else if(i==6) {num_2=max(1,num_2);num_3=max(1,num_3);}
        else if(i==7) num_7=1;
        else if(i==8) num_2=3;
        else if(i==9) num_3=2;
        if(up&&i==num[len-1]) res+=dfs(len-1,i,1,(pre*10+i)%2520,num_2,num_3,num_5,num_7);
        else res+=dfs(len-1,i,0,(pre*10+i)%2520,num_2,num_3,num_5,num_7);
        num_2=num2,num_3=num3,num_5=num5,num_7=num7;
    }
    if(!up) dp[len][digit][pre][num_2][num_3][num_5][num_7]=res;
    return res;
}
ll solve(ll x){
    ll ans=0;
    int tot=0;
    while(x){
        num[++tot]=x%10;
        x/=10;
    }
    num[tot+1]=0;
    ans=dfs(tot+1,0,1,0,0,0,0,0);
    return ans;
}
int main(){
    int t;
    ll n,m;
    cin>>t;
    memset(dp,-1,sizeof(dp));
    while(t--){
        cin>>n>>m;
        cout<<solve(m)-solve(n-1)<<endl;
    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

B-HDU4352

题解:

题意大致是让你求[l,r]区间其LIS刚好为k的个数。

这里一开始往建立10!的数组去维护最后一位是i的LIS值(肯定T且存不下)

之后想这nlogn的LIS求法中找到启发,即只要维护一个递增的数列即可,且数列个数不超过10 这样就可以用 2 n 2^n 2n, n = 10 n=10 n=10的状态去表示这个数列。

即可得到一个这样的状态dp[20][4086][11]即可求解。

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[22][2050][12],num[22];
int k;
ll dfs(int len,bool up,int pre,bool zero){
    if(len==1){
        if(zero&&k==1) return 1;
        int tmp=0;
        for(int i=1;i<=10;i++){
            if(pre&(1<<(i-1))) tmp++;
        }
        if(tmp==k) return 1;
        return 0;
    }
    if(dp[len][pre][k]!=-1&&!up&&!zero) return dp[len][pre][k];
    ll res=0;
    for(int i=0;i<=(up?num[len-1]:9);i++){
        int zj=-1;
        for(int j=i;j<=9;j++){
            if(pre&(1<<(j))){
                zj=j;
                break;
            }
        }
        if(!up||(up&&i==num[len-1])){
            if(i>0||!zero)
                res+=dfs(len-1,up,zj!=-1?pre-(1<<zj)+(1<<i):pre+(1<<i),0);
            else
                res+=dfs(len-1,up,pre,1);
        }
        else {
            if(i>0||!zero)
                res+=dfs(len-1,!up,zj!=-1?pre-(1<<zj)+(1<<i):pre+(1<<i),0);
            else
                res+=dfs(len-1,!up,pre,1);
        }
    }
    //cout<<len<<' '<<pre<<' '<<res<<endl;
    if(!zero&&!up){
        dp[len][pre][k]=res;
    }
    return res;
}
ll solve(ll x){
    int tot=0;
    if(x==0&&k==1) return 1;
    else if(x==0&&k!=1) return 0;
    while(x){
        num[++tot]=x%10;
        x/=10;
    }
    return dfs(tot+1,1,0,1);
}
int main(){
    //freopen("1.txt","r",stdin);
    ll n,m;
    int t;
    scanf("%d",&t);
    memset(dp,-1,sizeof(dp));
    for(int i=1;i<=t;i++){
        scanf("%lld%lld%d",&n,&m,&k);
        printf("Case #%d: %lld\n",i,solve(m)-solve(n-1));
    }

    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

C HDU2089

裸的数位dp

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}

int dp[20][20];
int Len,num[20];
int solve(int len,int digit,bool up){
    int res=0;
    if(digit==4||len<=0) return 0;
    if((len==1||!up)&&dp[len][digit]) return dp[len][digit];
    //cout<<num[len-1]<<"----"<<endl;
    for(int i=0;i<=(up?num[len-1]:9);i++){
        if(digit==6&&i==2) continue;
        //cout<<i<<endl;
        if((up&&i==num[len-1])||!up) res+=solve(len-1,i,up);
        else res+=solve(len-1,i,!up);
    }
    if(!up){
        dp[len][digit]=res;
    }
    //cout<<len<<' '<<digit<<' '<<up<<' '<<res<<endl;
    return res;
}
int cla(int x){
    int tot=0,ans=0;
    if(x==0) return 1;
    while(x){
        num[++tot]=x%10;
        x/=10;
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=9;i++){
        dp[1][i]=1;
    }
    for(int i=0;i<=num[tot];i++){
        if(i==num[tot]) ans+=solve(tot,i,1);
        else ans+=solve(tot,i,0);
    }
    return ans;
}
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0) break;
        printf("%d\n",cla(m)-cla(n-1));

    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

D HDU3555

裸体

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}

int dp[20][20];
int Len,num[20];
int solve(int len,int digit,bool up){
    int res=0;
    if(digit==4||len<=0) return 0;
    if((len==1||!up)&&dp[len][digit]) return dp[len][digit];
    //cout<<num[len-1]<<"----"<<endl;
    for(int i=0;i<=(up?num[len-1]:9);i++){
        if(digit==6&&i==2) continue;
        //cout<<i<<endl;
        if((up&&i==num[len-1])||!up) res+=solve(len-1,i,up);
        else res+=solve(len-1,i,!up);
    }
    if(!up){
        dp[len][digit]=res;
    }
    //cout<<len<<' '<<digit<<' '<<up<<' '<<res<<endl;
    return res;
}
int cla(int x){
    int tot=0,ans=0;
    if(x==0) return 1;
    while(x){
        num[++tot]=x%10;
        x/=10;
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=9;i++){
        dp[1][i]=1;
    }
    for(int i=0;i<=num[tot];i++){
        if(i==num[tot]) ans+=solve(tot,i,1);
        else ans+=solve(tot,i,0);
    }
    return ans;
}
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0) break;
        printf("%d\n",cla(m)-cla(n-1));

    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

E POJ-3252

题解:

记录一维0的个数记录一维1的个数即可

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[66][3][66][66],num[66];
ll dfs(int len,int digit,bool up,bool pre,int numb,int pp){
    if(len==1){
        //cout<<numb<<' '<<pp<<' '<<digit<<endl;
        if(numb*2<=pp) return 1;
        else return 0;
    }
    ll res=0;
    if(dp[len][digit][numb][pp]&&!up) return dp[len][digit][numb][pp];
    for(int i=0;i<=(up?num[len-1]:1);i++){
        if(up&&i==num[len-1]){
            res+=dfs(len-1,i,up,0,numb+i,pp+1);
        }
        else if(!up){
            if(!pre) res+=dfs(len-1,i,up,pre,numb+i,pp+1);
            else {
                if(i==1){
                    res+=dfs(len-1,i,up,0,numb+i,pp+1);
                }
                else {
                    res+=dfs(len-1,i,up,1,numb,pp);
                }
            }
        }
        else {
            res+=dfs(len-1,i,!up,0,numb+i,pp+1);
        }
    }
    if(!up){
        dp[len][digit][numb][pp]=res;
    }
    return res;
}
ll solve(ll x){
    ll ans=0;
    int tot=0;
    if(x==0) return 1;
    memset(dp,0,sizeof(dp));
    while(x){
        num[++tot]=x%2;
        x/=2;
    }
    ans+=dfs(tot,1,1,0,1,1);
    ans+=dfs(tot,0,0,1,0,0);
    /*for(int i=1;i<=tot;i++){
        for(int j=0;j<=tot;j++){
            for(int p=j;p<=tot;p++){
                cout<<i<<' '<<j<<' '<<p<<endl;
                cout<<dp[i][0][j][p]<<' '<<dp[i][1][j][p]<<endl;
            }
        }
    }*/
    //cout<<ans<<endl;
    return ans;
}
int main(){
    ll n,m;
    cin>>n>>m;
    cout<<solve(m)-solve(n-1)<<endl;
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

F HDU-3709

题解:

存一维中轴 一维和(中轴左为+右为-)这样这要开 5000 5000 5000大小就绰绰有余

我的 d p dp dp状态是 d p [ 21 ] [ 21 ] [ 4000 ] [ 2 ] [ 2 ] dp[21][21][4000][2][2] dp[21][21][4000][2][2] 2 2 2维其实可以省掉

(在这里学会了 m e m s e t memset memset只需执行 1 1 1次即可,不然会 T T T

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[21][21][4001][2][2];
ll num[21];
ll dfs(int len,bool up,int pre,int mi,bool zero){
    ll res=0;
    if(len==1){
        if(pre==2000) return 1;
        else return 0;
    }
    if(!zero&&len-1<mi) return 0;
    if(!up&&dp[len][mi][pre][zero][0]!=-1&&mi>len) return dp[len][mi][pre][zero][0];
    if(!up&&dp[len][mi][pre][zero][1]!=-1&&mi<=len) return dp[len][mi][pre][zero][1];
    for(int i=0;i<=(up?num[len-1]:9);i++){
        if(i>=1) zero=true;
        if(up){
            //cout<<"YES"<<endl;
            if(i==num[len-1]) res+=dfs(len-1,up,pre+(len-1-mi)*i,mi,zero);
            else res+=dfs(len-1,!up,pre+(len-1-mi)*i,mi,zero);
        }
        else res+=dfs(len-1,up,pre+(len-1-mi)*i,mi,zero);
    }
    if(!up){
        if(mi>len)
            dp[len][mi][pre][zero][0]=res;
        else
            dp[len][mi][pre][zero][1]=res;
    }
    return res;
}
ll solve(ll x){
    int tot=0;
    ll ans=0;
    if(x<0) return 0;
    else if(x==0) return 1;
    while(x){
        num[++tot]=x%10;
        x/=10;
    }
    for(int i=1;i<=tot;i++){
        ans+=dfs(tot+1,1,2000,i,0);
    }
    return ans;
}
int main(){
    //freopen("1.txt","r",stdin);
    int t;
    ll n,m;
    memset(dp,-1,sizeof(dp));
    scanf("%d",&t);
    while(t--){
        scanf("%I64d%I64d",&n,&m);
        printf("%I64d\n",solve(m)-solve(n-1));
    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

G HDU-3652

裸体

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[20][11][20][3];
int num[20];
ll dfs(int len,int digit,bool up,int pre,bool mark){
    ll res=0;
    if(len==1){
        if(pre==0&&mark) return 1;
        else return 0;
    }
    if(!up&&dp[len][digit][pre][mark]!=-1) return dp[len][digit][pre][mark];
    for(int i=0;i<=(up?num[len-1]:9);i++){
        bool tmp=mark;
        if(digit==1&&i==3) tmp=true;
        if(up){
            if(i==num[len-1]) res+=dfs(len-1,i,up,(pre*10+i)%13,tmp);
            else res+=dfs(len-1,i,!up,(pre*10+i)%13,tmp);
        }
        else res+=dfs(len-1,i,up,(pre*10+i)%13,tmp);
    }
    if(!up){
        dp[len][digit][pre][mark]=res;
    }
    return res;
}
ll solve(ll x){
    int tot=0;
    ll ans=0;
    while(x){
        num[++tot]=x%10;
        x/=10;
    }
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<=num[tot];i++){
        if(i==num[tot]) ans+=dfs(tot,i,1,i,0);
        else ans+=dfs(tot,i,0,i,0);
    }
    return ans;
}
int main(){
    ll n;
    while(~scanf("%lld",&n)){
        printf("%lld\n",solve(n));
    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

H HDU-4734

题解:

d p [ p o s ] [ n u m ] dp[pos][num] dp[pos][num] 表示在该位上比 n u m num num小的数的个数
即可写出如下转移
d p [ p o s ] [ n u m ] = dp[pos][num]= dp[pos][num]= ∑ \sum d p [ p o s − 1 ] [ n u m − d i g i t ∗ ( 1 &lt; &lt; ( p o s − 1 ) ) ] dp[pos-1][num-digit*(1&lt;&lt;(pos-1))] dp[pos1][numdigit(1<<(pos1))]
之后就是正常的数位dp过程

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll dp[11][10000],num[11];
ll dfs(int len,int numb,bool up){
    if(numb<0) return 0;
    if(len==0) return 1;
    if(dp[len][numb]!=-1&&!up) return dp[len][numb];
    ll res=0;
    for(int i=0;i<=(up?num[len]:9);i++){
        if(up&&i==num[len])
            res+=dfs(len-1,numb-i*(1<<(len-1)),1);
        else
            res+=dfs(len-1,numb-i*(1<<(len-1)),0);
    }
    if(!up){
        dp[len][numb]=res;
    }
    return res;
}
ll solve(ll x,ll y){
    int tot=0;
    ll ans=0;
    while(x){
        num[++tot]=x%10;
        x/=10;
    }
    ll maxn=0;
    ll p=1;
    while(y){
        maxn+=p*(y%10);
        p*=2LL;
        y/=10;
    }
    //memset(dp,-1,sizeof(dp));
    //cout<<tot<<' '<<maxn<<endl;
    ans=dfs(tot,maxn,1);
    return ans;
}
int main(){
    int t;
    int ti=0;
    ll a,b;
    scanf("%d",&t);
    memset(dp,-1,sizeof(dp));
    while(t--){
        scanf("%lld%lld",&a,&b);
        printf("Case #%d: %lld\n",++ti,solve(b,a));
    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

J HDU-4507

题解:

此题不让我们计数 而是让我求所有可行数的平方和

这类问题还是可以用数位dp解决(平方和与和、个数有关)

令个数为ant,和为sum,平方和为squre

因为我们可以发现在统计到pos位时 pos-1位的所有数的和是可以求出来的

sum[pos]=sum[pos-1]+digit*10^(pos-1)*ant[pos-1]

平方和又可以展开成

s q u r e [ p o s ] squre[pos] squre[pos]= ( ( d i g i t ∗ 1 0 ( p o s − 1 ) ) 2 ∗ a n t [ p o s − 1 ] ((digit*10^(pos-1))^2*ant[pos-1] ((digit10(pos1))2ant[pos1]+ 2 ∗ s u m [ p o s − 1 ] ∗ d i g i t ∗ 1 0 ( p o s − 1 ) + s q u r e [ p o s − 1 ] 2*sum[pos-1]*digit*10^(pos-1)+squre[pos-1] 2sum[pos1]digit10pos1+squre[pos1]

(可以尝试推一推)
(比较坑的是容易爆long long 所以处理好mod即可)

代码:

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
#define INF 1073741824
#define inf 1152921504606846976
#define pi 3.14159265358979323846
//#pragma comment(linker,"/STACK:10240000,10240000")
const int N=3e5+7,M=2e6;
const long long mod=1e9+7;
inline int read(){int ret=0;char ch=getchar();bool f=1;for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');for(;isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48;return f?ret:-ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll ksm(ll a,ll b,ll mod){int ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b>>=1;}return ans;}
ll inv2(ll a,ll mod){return ksm(a,mod-2,mod);}//ÄæÔª
//int head[N],NEXT[N],ver[N],tot;void link(int u,int v){ver[++tot]=v;NEXT[tot]=head[u];head[u]=tot;}
ll num[20];
ll mul(ll x,ll y){
    return ((x)%mod)*((y)%mod)%mod;
}
struct node{
    ll ant;
    ll sum;
    ll squar;
    void INIT(){
        ant=-1;
        sum=0;
        squar=0;
    }
    void init(){
        ant=sum=squar=0;
    }
}dp[20][10][8][8];
ll P[22];
node dfs(int len,ll digit,bool up,int pre,int pre_){
    node res,Next;
    res.init();
    //cout<<res.squar<<res.ant<<res.sum<<endl;
    if(len==1){
        if(pre!=0&&pre_!=0&&digit!=7) {
            res.ant=1;
            res.sum=digit;
            res.squar=digit*digit;
            return res;
        }
        else return res;
    }
    if(dp[len][digit][pre][pre_].ant!=-1&&!up) return dp[len][digit][pre][pre_];
    for(ll i=0;i<=(up?num[len-1]:9);i++){
        //cout<<len<<' '<<i<<endl;
        if(i==7) continue;
        if(up){
            if(i==num[len-1]) Next=dfs(len-1,i,up,(pre+i)%7,(pre_*10+i)%7);
            else Next=dfs(len-1,i,!up,(pre+i)%7,(pre_*10+i)%7);
        }
        else Next=dfs(len-1,i,up,(pre+i)%7,(pre_*10+i)%7);
        res.ant+=Next.ant;
        //res.sum+=(next.ant*((digit*P[len-1])%mod))%mod;
        res.sum+=(mul(mul(1LL,Next.ant),mul(digit,P[len-1])));
        res.sum%=mod;
        res.sum+=Next.sum;
        res.sum%=mod;
        res.squar+=mul(mul(mul(digit,P[len-1]),mul(digit,P[len-1])),mul(1LL,Next.ant));
        //res.squar+=(((((digit*P[len-1])%mod)*((digit*P[len-1])%mod))%mod)*next.ant)%mod;
        res.squar%=mod;
        res.squar+=mul(2LL,mul(Next.sum,mul(digit,P[len-1])));
        //res.squar+=(2LL*((next.sum*((digit*P[len-1])%mod))%mod))%mod;
        res.squar%=mod;
        res.squar+=Next.squar;
        res.squar%=mod;
        //cout<<"------"<<endl;
        //cout<<res.ant<<endl;
        //cout<<res.squar<<endl;
        //cout<<res.sum<<endl;
        //cout<<"-----"<<endl;
    }
    //cout<<len<<' '<<digit<<' '<<pre<<' '<<pre_<<' '<<res.ant<<' '<<res.sum<<' '<<res.squar<<endl;
    if(!up){
        dp[len][digit][pre][pre_]=res;
    }
    return res;
}
ll solve(ll x){
    int tot=0;
    node ans;
    while(x){
        num[++tot]=x%10;
        x/=10;
    }
    ans=dfs(tot+1,0,1,0,0);
    return ans.squar;
}
int main(){
    P[0]=1;
    for(int i=1;i<=20;i++){
        P[i]=P[i-1]*10LL;
        P[i]%=mod;
        //cout<<P[i]<<' '<<endl;
    }
    int t;
    for(int i=0;i<20;i++)
    for(int j=0;j<10;j++)
    for(int k=0;k<8;k++)
    for(int p=0;p<8;p++)
        dp[i][j][k][p].INIT();
    ll n,m;
    scanf("%d",&t);
    while(t--){
        scanf("%I64d%I64d",&n,&m);
        printf("%I64d\n",(solve(m)-solve(n-1)+mod)%mod);
    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值