传送门
这道题要求我们求[l,r]范围内所有的“蛇数”,即这个数的第一位严格大于它的其他位的数。
看到数据范围并且发现答案区间可加减性联想到数位DP。其实有点类似模板题,与经典的数位DP题类似的,我们需要判断前导0,需要判断当前枚举的数是否是贴着所给的数,在此题中如果想要记忆化的话,还需要加两个量,即d表示当前枚举的数首位是什么,还有st表示当前枚举的数首位在什么位置,这两个是为了dp数组记忆化服务,若是没有这两个的话dp数组就没办法精确地记录各种情况的答案。
代码:
#include<bits/stdc++.h>
using namespace std;
long long t;
const long long N = 2e5 + 10;
long long l,r;
long long dp[20][20][20][20];
vector<long long> digit;
long long dfs(long long pos,long long statu,long long d,long long lead,long long done,long long st) {
//pos:当前从高到低枚举到的位置,statu:上一个数是多少(其实可要可不要),d:当前枚举的数首位是多少,lead:当前是否是前导0,done:当前枚举的数是否贴着所给的数,st:当前枚举的数第一位是什么
if(pos == -1) return 1;
if(!lead && !done && ~dp[pos][statu][st][d] && d) return dp[pos][statu][st][d];
long long res = 0,end = done ? digit[pos] : 9;
for(long long i = 0;i <= end;i++) {
if(d && i >= d) continue;
bool flag = (lead && !i);
long long tmp,ss;
if(lead && flag) tmp = 0,ss = 0;
else if(lead && !flag) tmp = i,ss = pos;
else tmp = d,ss = st;
res += dfs(pos-1,i,tmp,flag,done && i == end,ss);
}
if(!done && !lead) dp[pos][statu][st][d] = res;
return res;
}
long long work(long long k) {
memset(dp,-1,sizeof dp);
digit.clear();
while(k) {
digit.push_back(k % 10);
k /= 10;
}
return dfs(digit.size()-1,0,0,1,1,0);
}
void solve() {
cin >> l >> r;
cout << work(r) - work(l-1);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
t = 1;
while(t--) solve();
return 0;
}
标签:ABC,&&,lead,pos,long,st,Snake,此题,dp
From: https://www.cnblogs.com/lwiwi/p/18665372