abc387c题解
竟然出了数位动态规划?在第三题?蒟蒻疑惑。
建议查看模版以学习。
我们先来看代码:链接。
看到这道题,显然看出是一道非常典型的数位动态规划。
怎么整?
注意到这题的限制条件变成了枚举每一位的大小不能超过首位,那么我们考虑修改记忆化搜索中的
在模版中,
修改完这一个定义,我们再看搜素代码。
int dfs(int p,int r,bool z,bool lmt){
if(p==0)return 1;
if(!lmt&&f[p][r]>-1)return f[p][r];
int ans=0,mx=(lmt?c[p]:9);
for(int i=0;i<=mx;i++){
if(!z&&i>=r&&r!=0)continue;
if(z&&i==0)ans+=dfs(p-1,0,1,lmt&&(i==mx));
else ans+=dfs(p-1,(r==0?i:r),0,lmt&&(i==mx));
}
if(!lmt&&!z)f[p][r]=ans;
return ans;
}
int func(int x){
memset(f,-1,sizeof(f));
s=to_string(x);
n=s.size();
for(int i=1;i<=n;i++)c[n-i+1]=s[i-1]-'0';
return dfs(n,0,1,1);
}
首先,我们记搜的精髓就是记忆,这里用
当然,答案可能为
考虑一直用的边界需要限制,加入
接着我们转移。
要是某一次数还是
要是我们将
否则我们要判断第一次让数从
感觉转移还是浅显易懂。
然后是剩下的。
我们的求解函数应该把开头
最后放板子和此题来对比下。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=205;
int a,b,c[N],cur,n,f[N][N];
string s;
int dfs(int p,int r,bool z,bool lmt){
if(p==0)return 1;
if(!lmt&&f[p][r]>-1)return f[p][r];
int ans=0,mx=(lmt?c[p]:9);
for(int i=0;i<=mx;i++){
if(!z&&abs(i-r)<2)continue;
if(z&&i==0)ans+=dfs(p-1,i,1,lmt&&(i==mx));
else ans+=dfs(p-1,i,0,lmt&&(i==mx));
}
if(!lmt&&!z)f[p][r]=ans;
return ans;
}
int func(int x){
memset(f,-1,sizeof(f));
s=to_string(x);
n=s.size();
for(int i=1;i<=n;i++)c[n-i+1]=s[i-1]-'0';
return dfs(n,-2,1,1);
}
signed main(){
cin>>a>>b;
cout<<func(b)-func(a-1);
return 0;
}
这题:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=205;
int a,b,c[N],cur,n,f[N][N];
string s;
int dfs(int p,int r,bool z,bool lmt){
if(p==0)return 1;
if(!lmt&&f[p][r]>-1)return f[p][r];
int ans=0,mx=(lmt?c[p]:9);
for(int i=0;i<=mx;i++){
if(!z&&i>=r&&r!=0)continue;
if(z&&i==0)ans+=dfs(p-1,0,1,lmt&&(i==mx));
else ans+=dfs(p-1,(r==0?i:r),0,lmt&&(i==mx));
}
if(!lmt&&!z)f[p][r]=ans;
return ans;
}
int func(int x){
memset(f,-1,sizeof(f));
s=to_string(x);
n=s.size();
for(int i=1;i<=n;i++)c[n-i+1]=s[i-1]-'0';
return dfs(n,0,1,1);
}
signed main(){
cin>>a>>b;
cout<<func(b)-func(a-1);
return 0;
}
是不是很像?