洛谷P2657 [SCOI2009] windy 数
洛谷1587: 【例 3】Windy 数
数位dp裸题
这道题对于前导0加个特判就好
如果前面是前导0,那么搜索时把pre赋值成-2(当然<-2的数都可以)
注意:这样处理之后dp数组就不能定义为dp[pos][pre][flag][lim](不懂的话见代码注释)。
因为pre哪里可能会是负数,所以只能有前两维,记忆化赋值的时候加特判,判断前面不是前导0,再赋值
不多说了,直接看代码吧(有注释)
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
ll l, r, len;
ll num[20], dp[15][15]; //dp[pos][pre]:处理到第i位,上一位为j,且当前位可以取0~9,不是全部都为0时的方案数
//注意:这里不能dp[pos][pre][flag][lim](原因见下)
ll dfs(ll pos, ll pre, ll flag, ll lim){ //pos:处理到第几位,pre:上一位是多少,flag:前面是否为前导0,lim:是否有上限
if(pos == len + 1) return 1;
if(!lim && dp[pos][pre] != -1) return dp[pos][pre]; //记忆化,这里只记忆了没有上限情况下的方案数
ll res = lim ? num[len - pos + 1] : 9; //找上限,注意这里是倒着存的数,所以num[len-pos+1]
ll ans = 0;
for(ll i = 0; i <= res; i++){
if(abs(i - pre) < 2) continue; //相差<2则continue
if(flag && !i) ans += dfs(pos + 1, -2, 1, lim && (i == res)); //如果前面为前导0,pre赋值成-2
else ans += dfs(pos + 1, i, 0, lim && (i == res)); //不是前导0的话正常dfs
}
if(!flag && !lim) dp[pos][pre] = ans; //特判,前面不是前导0,且没有上限,记忆化
return ans;
}
ll solve(ll x){
len = 0;
while(x){
num[++len] = x % 10;
x /= 10;
}
memset(dp, -1, sizeof(dp));
return dfs(1, -2, 1, 1);
}
signed main(){
scanf("%lld%lld", &l, &r);
printf("%lld\n", solve(r) - solve(l - 1));
return 0;
}
完结撒花~
本文作者:xixike
本文链接:https://www.cnblogs.com/xixike/p/15102630.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步