学了一下数位DP后才会做范老师的题目。
HDU2689不要62
模板题 , dfs写法,大概理解数位dp的思想以及简洁的写法。limit:是否受限,zero:是否一直在前导零。数位dp的精髓在于记忆化搜索。
#include<bits/stdc++.h>
using namespace std;
const int N = 10000;
int dp[N][2] , l , r , ans , a[N] , cnt;
int dfs(int pos ,int six , int limit) {
if(!pos) return 1;
if(!limit && dp[pos][six] != -1) return dp[pos][six];
int up = limit ? a[pos] : 9;
int res = 0;
for(int i = 0;i <= up;i ++) {
if(i == 4) continue;
if(six && i == 2) continue;
res += dfs(pos - 1, i == 6, a[pos] == i && limit);
}
if(!limit) dp[pos][six] = res;
return res;
}
int solve(int x) {
cnt = 0;
while(x) {
a[++ cnt] = x % 10;
x /= 10;
}
return dfs(cnt , 0 , 1);
}
int main() {
memset(dp,-1,sizeof(dp));
while(scanf("%d%d",&l,&r) == 2 && l + r) {
printf("%d\n",solve(r) - solve(l - 1));
}
}
BZOJ1026 Windy数
考虑前导零和limit细节不多,模版思路跟着走即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 35;
int dp[N][15] , n , m , l , r , cnt , a[N];
int dfs(int pos ,int limit , int lead, int sta) {
if(!pos) return 1;
if(!limit && !lead && dp[pos][sta] != -1) return dp[pos][sta];
int up = limit ? a[pos] : 9;
int res = 0;
for(int i = 0;i <= up;i ++) {
if(abs(i - sta) <= 1) continue;
res += dfs(pos - 1 , a[pos] == i && limit , lead && (!i),(lead && (!i)) ? -100 : i);
}
if(!limit && !lead) dp[pos][sta] = res;
return res;
}
int solve(int x) {
cnt = 0;
while(x) {
a[++ cnt] = x % 10;
x /= 10;
}
return dfs(cnt , 1 , 1 , -100);
}
int main() {
memset(dp,-1,sizeof(dp));
scanf("%d%d",&l,&r);
printf("%d\n",solve(r) - solve(l - 1));
}
最后就是一道比较神的数位DP,范老师的T3