数位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多字了,已经开始卡了,所以会分多期。