数位DP
模板题:1082. 数字游戏
题目描述
求整数区间 [L,R][L,R] 内, 不降数 的个数
不降数:数位从高到低呈非下降关系(【例】:123,446)
代码
#include <bits/stdc++.h> using namespace std; typedef long long LL; #define N 15 int f[N][N];//f[i][j]表示i位数且最高位(最左端为最高位)为j的不降序的方案数 void init(){ for(int i=0;i<=9;i++) f[1][i]=1; for(int i=2;i<N;i++) for(int j=0;j<=9;j++) for(int k=j;k<=9;k++){ f[i][j]+=f[i-1][k]; // cout<<i<<" "<<j<<" "<<f[i][j]<<endl; } } int dp(int n){ if(n==0) return 1; vector<int> nums; while(n) nums.push_back(n%10),n/=10; // cout<<n<<endl; // cout<<nums[0]<<endl; int ans=0; int last=0; for (int i=nums.size()-1; i>=0; i--){ int x=nums[i]; for(int j=last;j<x;j++) ans+=f[i+1][j]; if(last>x) break; last=x; if(!i) ans++;//全部枚举到最低位的右分支。 } return ans; } signed main() { init(); int n,m; while(cin>>n>>m) // cout<<n<<m<<" "<<dp(n-1)<<endl; printf("%d\n",dp(m)-dp(n-1)); return 0; }
1083. Windy数
思路:
数位Dp
假设我们当前枚举到第i位(设共有n位),且第i位上的数字为x,那么对于答案中第i位数字j来说,有两类:
1.0~x-1 (如果第i位是最高位,这里是1~x-1)
括号中提到的1~x-1后面会解释 ,我们用last记录上一位的数字,然后枚举j,如果abs(j-last) >= 2 就累加答案,res += f[i+1][j];
2.x
不需要枚举j,last = x,再枚举之后的数位即可
上述做完之后,由于上面的答案都是n位的,对于数位个数低于n的,再累加到答案中就行了
f数组的处理
f[i][j] 表示一共有i位,且最高位数字为j的满足windy数定义的数的个数
状态转移: 因为第i位是j已经确定,考虑第i-1位,设第i-1位数字为k,那么根据windy数定义只要abs(k-j) >= 2就可以转移过来
关于前导0
上面提到了枚举的第i位是最高位,那么不能填0,这里解释一下,如果我们填0,那么答案就会加上f[i+1][0],,举这样一个例子,
对于数字13,他是满足windy数定义的,那么加上前导0之后的013就不会被f[3][0]加进去,原因就是abs(0-1)<2,这样就导致答案漏掉。
作者:Moon_light
链接:https://www.acwing.com/solution/content/15562/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
代码:
#include<bits/stdc++.h> using namespace std; #define int long long const int mod=998244353; const int N=11; int f[N][N]; //f[i][j] 表示一共有i位, //且最高(左边为高位)为是数字j的满足wingy数定义的数的个数 void init(){ for(int i=0;i<=9;i++) f[1][i]=1; for(int i=2;i<=N;i++) for(int j=0;j<=9;j++) for(int k=0;k<=9;k++) if(abs(k-j)>=2) f[i][j]+=f[i-1][k]; } int dp(int n){ int ans=0; int last=-2; vector<int> vec; while(n) vec.push_back(n%10) ,n/=10; int len=vec.size()-1; //答案是len位的情况 for(int i=len;i>=0;i--){ int x=vec[i]; for(int j=(i==len);j<x;j++){//最高位从1开始 if(abs(j-last)>=2) ans+=f[i+1][j]; } if(abs(x-last)<2) break; last=x; if(!i) ans++; } //答案小于a.size()位的 for(int i = 1; i<=len; i++) for(int j = 1; j<=9; j++) ans += f[i][j]; return ans; } signed main(){ init(); int n,m; cin>>n>>m; cout<<dp(m)-dp(n-1)<<endl; return 0; }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16724419.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2021-09-23 三分算法