数位DP学习
我是参考Pecco大佬的这篇文章学习的:算法学习笔记(68): 数位DP -
知乎 (zhihu.com),可以先看看,或者复习后再看看下面的题。
题单是这个:(提高)『数位DP』从入门到入土
- 题单 - 洛谷 | 计算机科学教育新生态
(luogu.com.cn),目前写了十多道,会慢慢补的。
也许以后会再补充一些其他OJ上的题目?
数位DP文章例题
先附上文章里的题目吧~~~
#include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); int a[10],dp[8][12][2]; int cnt;    
 
 
 
 
 
  int dfs(int pos,int last,bool limit) {     int ans=0;     if(pos==cnt)return 1;        if(dp[pos][last][limit]!=-1)return dp[pos][last][limit];     for(int i=0;i<=(limit?a[pos]:9);i++)     {         if(last==6&&i==2 || i==4)   continue;         ans+=dfs(pos+1,i,limit&&i==a[pos]);     }     dp[pos][last][limit]=ans;     return ans; } int f(int x) {     cnt=0;     memset(a,0,sizeof(a));     memset(dp,-1,sizeof(dp));        while(x)     {         a[cnt++]=x%10;         x/=10;     }     std::reverse(a,a+cnt);     return dfs(0,11,true);   } void solve() {     int x,y;     while(std::cin>>x>>y,(x||y))     {         int l=f(x-1),r=f(y);         std::cout<<r-l<<"\n";     } } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve();     return 0; }
   | 
 
 #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); ll a[10],dp[15][12][2][2];
 
 
 
 
  ll cnt,digit; ll dfs(int pos,int cntd,bool limit,bool lead) {     ll ans=0;     auto &d=dp[pos][cntd][limit][lead];     if(pos==cnt)    return d;     if(dp[pos][cntd][limit][lead]!=-1)  return dp[pos][cntd][limit][lead];     for(int i=0;i<=(limit?a[pos]:9);i++)     {         if(lead && i==0)    ans+=dfs(pos+1,cntd,limit && i==a[pos],true);         else ans+=dfs(pos+1,cntd+(i==digit),limit && i==a[pos],false);     }     dp[pos][cntd][limit][lead]=ans;     return ans; } ll f(ll x) {     cnt=0;     memset(a,0,sizeof(a));     memset(dp,-1,sizeof(dp));        while(x)     {         a[cnt++]=x%10;         x/=10;     }     std::reverse(a,a+cnt);     return dfs(0,0,true,true); } void solve() {     ll x,y; std::cin>>x>>y;     for(int i=0;i<10;i++)     {         digit=i;         ll l=f(x-1),r=f(y);         std::cout<<r-l<<" ";     } } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve();     return 0; }
 
  | 
 
#include<bits/stdc++.h> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); ll a[64],b[64],dp[64][2][2][2][2];
 
 
 
 
  ll cnt1,cnt2,cnt;
 
 
  ll dfs(int pos,bool limitl1,bool limitr1,bool limitl2,bool limitr2) {     if(pos==cnt)    return 0;        auto &d=dp[pos][limitl1][limitr1][limitl2][limitr2];     if(d!=-1)     {         return d;     }     ll ans=0;     for(ll i=(limitl1?a[pos]:0);i<=(limitr1?b[pos]:1);i++)     {         for(ll j=(limitl2?a[pos]:0);j<=(limitr2?b[pos]:1);j++)         {             ans=std::max(ans,((i^j)<<(cnt-pos-1))+dfs(pos+1,limitl1 && i==a[pos],limitr1 && i==b[pos],limitl2 && j==a[pos], limitr2 && j==b[pos]));         }     }     d=ans;     return ans; } ll f(ll x,ll y) {     cnt1=0;     cnt2=0;     memset(dp,-1,sizeof(dp));        while(x)     {         a[cnt1++]=x&1;         x>>=1;     }     while(y)     {         b[cnt2++]=y&1;         y>>=1;     }     cnt=std::max(cnt1,cnt2);     std::reverse(a,a+cnt);     std::reverse(b,b+cnt);     return dfs(0,true,true,true,true); } void solve() {     ll x,y; std::cin>>x>>y;     std::cout<<f(x,y)<<"\n"; } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve();     return 0; }
   | 
 
这道题的正解做法其实是贪心,后面会写一篇文章来介绍。
(提高)『数位DP』从入门到入土
 #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); int cnt=0; ll a[22]; ll dp[22][200][2]; ll dfs(int pos,ll sum,bool limit) {     ll ans=0;     auto &d=dp[pos][sum][limit];     if(pos==cnt)    return sum;     if(d!=-1)   return d;     for(int i=0;i<=(limit?a[pos]:9);i++)     {         ans+=dfs(pos+1,sum+i,limit && i==a[pos]);         ans+=mod;         ans%=mod;     }     return d=ans; } ll f(ll x) {     cnt=0;     memset(dp,-1,sizeof(dp));     memset(a,0,sizeof(a));     while(x)     {         a[cnt++]=x%10;         x/=10;     }     std::reverse(a,a+cnt);     return dfs(0,0,true); } void solve() {     ll x,y;     std::cin>>x>>y;     ll l=f(x-1),r=f(y);          std::cout<<(r-l+mod)%mod<<"\n"; } int main() {     std::ios::sync_with_stdio(false);     int t=1;     std::cin>>t;     while(t--)solve();     return 0; }
 
  | 
 
 #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); ll a[64],dp[64][64][64][2][2];
 
 
 
  ll cnt; ll dfs(ll pos,ll cnt0,ll cnt1,bool limit,bool lead) {     ll ans=0;     if(pos==cnt)     {         return cnt0>=cnt1;     }     auto &d=dp[pos][cnt0][cnt1][limit][lead];     if(d!=-1)    return d;     for(int i=0;i<=(limit?a[pos]:1);i++)     {         if(lead && i==0)    ans+=dfs(pos+1,cnt0,cnt1,limit && i==a[pos],true);         else if(lead) ans+=dfs(pos+1,cnt0,cnt1+1,limit && i==a[pos],false);         else    ans+=dfs(pos+1,cnt0+(i==0),cnt1+(i==1),limit && i==a[pos],false);     }     d=ans;     return ans; } ll f(ll x) {     cnt=0;     memset(dp,-1,sizeof(dp));        memset(a,0,sizeof(a));     while(x)     {         a[cnt++]=x&1;         x>>=1;     }     std::reverse(a,a+cnt);     return dfs(0,0,0,true,true); } void solve() {     ll x,y; std::cin>>x>>y;     ll l=f(x-1),r=f(y);     std::cout<<r-l<<"\n"; } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve();     return 0; }
 
  | 
 
#include<bits/stdc++.h> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); int cnt=0; ll a[12]; ll dp[20][12][12][2][2];
 
 
 
 
 
 
  ll dfs(int pos,ll sum,int last,bool limit,bool lead) {     ll ans=0;     auto &d=dp[pos][sum][last][limit][lead];     if(pos==cnt)     {                  return sum;     }     if(d!=-1)   return d;     for(int i=0;i<=(limit?a[pos]:9);i++)     {         if(abs(i-last)>=2 || lead)         {                                                    ans+=dfs(pos+1,sum+((cnt==1)) || (i || !lead),i,limit && i==a[pos],lead && i==0);         }     }     d=ans;     return ans; } ll f(ll x) {     cnt=0;     memset(dp,-1,sizeof(dp));     memset(a,0,sizeof(a));     while(x)     {         a[cnt++]=x%10;         x/=10;     }     std::reverse(a,a+cnt);     return dfs(0,0,0,true,true); } void solve() {     ll x,y;     std::cin>>x>>y;     ll l=f(x-1),r=f(y);     if(x<10&&y<10)    std::cout<<r-l-1<<"\n";     else        std::cout<<r-l<<"\n";
  } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve();     return 0; }
   | 
 
看上面,这里不重复了。
#include<bits/stdc++.h> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); int cnt=0; ll a[12]; ll dp[12][90][2][2]; ll dfs(int pos,ll sum,bool limit,bool lead) {     ll ans=0;     auto &d=dp[pos][sum][limit][lead];     if(pos==cnt)     {         return sum;     }     if(d!=-1)   return d;     for(int i=0;i<=(limit?a[pos]:9);i++)     {         if(lead && i==0)    ans+=dfs(pos+1,sum,limit && i==a[pos],true);         else    ans+=dfs(pos+1,sum+i,limit && i==a[pos],false);     }     d=ans;     return ans; } ll f(ll x) {     cnt=0;     memset(dp,-1,sizeof(dp));     memset(a,0,sizeof(a));     while(x)     {         a[cnt++]=x%10;         x/=10;     }     std::reverse(a,a+cnt);     return dfs(0,0,true,true); } void solve() {     ll x,y;     std::cin>>y;     x=1;     ll l=f(x-1),r=f(y);     std::cout<<r-l<<"\n";
  } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve();     return 0; }
   | 
 
#include<bits/stdc++.h> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const int P=1e7+7; const double PI=acos(-1); int cnt=0; ll a[64]; ll dp[64][64][64][2]; ll ans[64]; ll dp2[64][64][2];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  ll dfs(int pos,int cnt1,int tot,bool limit) {     ll ans=0;     auto &d=dp[pos][cnt1][tot][limit];     if(pos==cnt)     {         return cnt1==tot;     }     if(d!=-1)   return d;     for(int i=0;i<=(limit?a[pos]:1);i++)     {         ans+=dfs(pos+1,cnt1+(i==1),tot,limit && i==a[pos]);     }     d=ans;     return ans; } ll qpower(ll a,ll n) {     ll ans=1;     while(n)     {         if(n&1) ans=a*ans%P;         a=a*a%P;         n>>=1;     }     return ans; } void solve() {     ll x,y;     std::cin>>y;     cnt=0;     memset(a,0,sizeof(a));     while(y)     {         a[cnt++]=y&1;         y/=2;     }     std::reverse(a,a+cnt);     for(int i=0;i<cnt;i++)     {         memset(dp,-1,sizeof(dp));         ans[i]=dfs(0,0,i+1,true);     }     ll res=1;     for(int i=0;i<cnt;i++)     {         res=res*qpower(i+1,ans[i])%P;     }     std::cout<<(res+P)%P<<"\n"; }
 
 
  ll dfs2(int pos,int cnt1,bool limit) {     ll ans=1;     auto &d=dp2[pos][cnt1][limit];     if(pos==cnt)     {         return std::max(cnt1,1);     }     if(d!=-1)   return d;     for(int i=0;i<=(limit?a[pos]:1);i++)     {         ans=ans*dfs2(pos+1,cnt1+(i==1),limit && i==a[pos])%P;     }     return d=ans; } void solve2() {     ll x,y;     std::cin>>y;     cnt=0;     memset(a,0,sizeof(a));     while(y)     {         a[cnt++]=y&1;         y>>=1;     }     memset(dp2,-1,sizeof(dp2));     std::reverse(a,a+cnt);     std::cout<<(dfs2(0,0,true)+P)%P; } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve2();     return 0; }
   | 
 
 #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); ll a[10],dp[15][12][2][2];
 
 
 
 
  ll cnt,digit; ll dfs(int pos,int cntd,bool limit,bool lead) {     ll ans=0;     if(pos==cnt)    return cntd;     if(dp[pos][cntd][limit][lead]!=-1)  return dp[pos][cntd][limit][lead];     for(int i=0;i<=(limit?a[pos]:9);i++)     {         if(lead && i==0)    ans+=dfs(pos+1,cntd,limit && i==a[pos],true);         else ans+=dfs(pos+1,cntd+(i==digit),limit && i==a[pos],false);     }     dp[pos][cntd][limit][lead]=ans;     return ans; } ll f(ll x) {     cnt=0;     memset(a,0,sizeof(a));     memset(dp,-1,sizeof(dp));        while(x)     {         a[cnt++]=x%10;         x/=10;     }     std::reverse(a,a+cnt);     return dfs(0,0,true,true); } void solve() {     ll x,y;     while(std::cin>>x>>y,x||y)     {         if(x>y)     std::swap(x,y);         for(int i=0;i<10;i++)         {             digit=i;             ll l=f(x-1),r=f(y);                          std::cout<<r-l<<(i<9?" ":"\n");         }     } } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve();     return 0; }
 
  | 
 
 #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); ll a[64],dp[64][1024][2][12];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  ll cnt; ll b; ll dfs(ll pos,int state,bool limit,bool lead) {     ll ans=0;     auto &d=dp[pos][state][lead][b];     if(!pos)    return state==0;     if(d!=-1 && !limit)  return d;     for(int i=0;i<=(limit?a[pos]:b-1);i++)     {         if(lead && i==0)    ans+=dfs(pos-1,false,limit && i==a[pos],true);         else    ans+=dfs(pos-1,state^(1<<i),limit && i==a[pos],false);     }     if(!limit)  d=ans;     return ans; } ll f(ll x) {     cnt=0;     while(x)     {         a[++cnt]=x%b;         x/=b;     }     return dfs(cnt,false,true,true); } void solve() {     ll x,y;     std::cin>>b>>x>>y;     ll l=f(x-1);     ll r=f(y);     std::cout<<r-l<<"\n"; } int main() {     std::ios::sync_with_stdio(false);     int t=1;     memset(dp,-1,sizeof(dp));     std::cin>>t;     while(t--)solve();     return 0; }
 
  | 
 
 #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); ll a[10],dp[15][12][2][2];
 
 
 
 
  ll cnt,digit; ll dfs(int pos,int cntd,bool limit,bool lead) {     ll ans=0;     if(pos==cnt)    return cntd;     if(dp[pos][cntd][limit][lead]!=-1)  return dp[pos][cntd][limit][lead];     for(int i=0;i<=(limit?a[pos]:9);i++)     {         if(lead && i==0)    ans+=dfs(pos+1,cntd,limit && i==a[pos],true);         else ans+=dfs(pos+1,cntd+(i==digit),limit && i==a[pos],false);     }     dp[pos][cntd][limit][lead]=ans;     return ans; } ll f(ll x) {     cnt=0;     memset(a,0,sizeof(a));     memset(dp,-1,sizeof(dp));        while(x)     {         a[cnt++]=x%10;         x/=10;     }     std::reverse(a,a+cnt);     return dfs(0,0,true,true); } void solve() {     ll x,y;     while(std::cin>>x>>y,x||y)     {         if(x>y)     std::swap(x,y);         for(int i=0;i<10;i++)         {             digit=i;             ll l=f(x-1),r=f(y);                          std::cout<<r-l<<(i<9?" ":"\n");         }     } } int main() {     std::ios::sync_with_stdio(false);     int t=1;          while(t--)solve();     return 0; }
 
  | 
 
 #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); ll a[22],dp[22][22][2]; int cnt; ll dfs(int pos,int cntd,bool limit,bool lead) {     ll ans=0;     auto &d=dp[pos][cntd][lead];     if(pos==0)      return cntd<=3;     if(!limit && d!=-1)   return d;     for(int i=0;i<=(limit?a[pos]:9);i++)     {         ans+=dfs(pos-1,cntd+(i!=0),limit && i==a[pos],lead && i==0);     }     if(!limit)  d=ans;     return ans; } ll f(ll x) {     cnt=0;     while(x)     {         a[++cnt]=x%10;         x/=10;     }     return dfs(cnt,0,true,true); } void solve() {     ll x,y;     std::cin>>x>>y;     ll l=f(x-1);     ll r=f(y);     std::cout<<r-l<<"\n"; } int main() {     std::ios::sync_with_stdio(false);     int t=1;     memset(dp,-1,sizeof(dp));     std::cin>>t;     while(t--)solve();     return 0; }
 
  | 
 
 #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); ll a[22],dp[22][180][200]; int cnt; int P;
 
 
 
 
 
 
 
  ll dfs(int pos,int sum,ll num,bool limit) {     ll ans=0;     auto &d=dp[pos][sum][num];     if(pos==0)      return num==0 && sum==P;         if(!limit && d!=-1)   return d;     for(int i=0;i<=(limit?a[pos]:9);i++)     {                  ans+=dfs(pos-1,sum+i,(10ll*num+i)%P,limit && i==a[pos]);     }     if(!limit)  d=ans;     return ans; } ll f(ll x) {     cnt=0;     while(x)     {         a[++cnt]=x%10;         x/=10;     }     ll ans=0;               for(P=1;P<=9*cnt;P++)     {         memset(dp,-1,sizeof(dp));            ans+=dfs(cnt,0,0,true);     }     return ans; } void solve() {     ll x,y;     std::cin>>x>>y;     ll l=f(x-1);     ll r=f(y);     std::cout<<r-l<<"\n"; } int main() {     std::ios::sync_with_stdio(false);     int t=1;               while(t--)solve();     return 0; }
 
  | 
 
#include<bits/stdc++.h> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using ll=long long; const int MAXN=1e5+10; const int mod=1e9+7; const double PI=acos(-1); int cnt,digit; ll a[20]; ll dp[20][20][2];
 
 
 
  ll dfs(int pos,int cntd,bool limit,bool lead) {     ll ans=0;     auto &d=dp[pos][cntd][lead];     if(pos==0)      return cntd;     if(d!=-1 && !limit)      return d;     for(int i=0;i<=(limit?a[pos]:9);i++)     {         if(lead && i==0)    ans+=dfs(pos-1,cntd,limit && i==a[pos],true);         else    ans+=dfs(pos-1,cntd+(i==digit),limit && i==a[pos],false);     }     if(!limit)  d=ans;     return ans; } ll f(ll x) {     memset(dp,-1,sizeof(dp));     cnt=0;     while(x)     {         a[++cnt]=x%10;         x/=10;     }     return dfs(cnt,0,true,true); } void solve() {     memset(a,0,sizeof(a));     ll ans=0;     ll x,y;     std::cin>>x>>y;     for(int i=0;i<10;i++)     {         digit=i;         ll l=f(x-1),r=f(y);         ans+=i*(r-l);     }     std::cout<<ans<<"\n"; } int main() {     std::ios::sync_with_stdio(false);     int t=1;     memset(dp,-1,sizeof(dp));     std::cin>>t;     while(t--)solve();     return 0; }
   | 
 
因为是保存在Typora上的,现在已经有5000多字了,已经开始卡了,所以会分多期。