HELLO W|

kingwzun

园龄:3年6个月粉丝:111关注:0

2022-09-23 21:21阅读: 22评论: 0推荐: 0

数位DP

模板题:1082. 数字游戏

题目描述
求整数区间 [L,R][L,R] 内, 不降数 的个数

不降数:数位从高到低呈非下降关系(【例】:123,446)

image
image

代码

#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就可以转移过来

f[i][j]=k=09if(abs(kj)>=2)f[i1][k]

关于前导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 中国大陆许可协议进行许可。

posted @   kingwzun  阅读(22)  评论(0编辑  收藏  举报
历史上的今天:
2021-09-23 三分算法
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起