飞往大厂梦之算法提升-day08
第一题:
题目描述
小明以他的名字命名了一种数——小明数。
对于一个十进制的数,若任意相邻两个数位的差值的绝对值不超过 K,则称其为小明数。
现小明给出一个区间 L,R,求区间 L,R 一共有多少个小明数。
输入描述
第 1 行为一个整数 T,表示测试数据数量。
输入仅一行,包含三个整数K,L,R。
1≤T≤105, 0≤K≤9, 1≤L≤R≤109。
输出描述
输出共 T 行,每行一个整数,表示每组数据的答案。
输入案例:
1
5 10 20
输出案例:
8
代码部分:
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
ll a[20];
ll dp[20][10][2][20];
int k;
ll dfs(int pos,bool limit,bool st,int p1,int is){if(pos<0)return is==1?1:0;if(!limit&&dp[pos][p1][st][is]!=-1)return dp[pos][p1][st][is];ll res=0;int up=limit?a[pos]:9;for(int i=0;i<=up;i++){res+=dfs(pos-1,limit&&(i==up),st||(i>0),i,!st||is&&(abs(i-p1)<=k));}if(!limit)dp[pos][p1][st][is]=res;return res;
}ll f(ll n){int pos=0;while(n){a[pos++]=n%10;n/=10;}return dfs(pos-1,true,false,0,1);
}int main(){int t;cin>>t;while(t--){memset(dp,-1,sizeof(dp));ll l,r;cin>>k>>l>>r;cout<<f(r)-f(l-1)<<'\n';}return 0;
}
这道题使用的还是数位DP的基本思想,但是这道题与普通的数位DP的区别是⚠️:
1.这道题要处理前置0的情况,所以必须要设置st来处理。
2.注意当有前置0的影响时,可以设置一个一开始值为1的状态,这个状态当还在处理前置0时,值一直为1不变,当!st即没有前置0时开始处理判断。
第二题:
问题描述
2023 年举办了第 14 届蓝桥杯,小蓝在这一年拿到了国一,因此他将这一年定为自己的幸运年。现在小蓝有一个问题,如果一个正整数包含 2023 或者包含 14,这个数就是幸运的。
现在他想知道在区间 [l,r] 之间有多少个幸运数字,你可以帮他求出来吗?
输入格式
输入二个正整数 l,r,代表区间范围。
输出格式
输出一个正整数 x ,代表幸运数字的个数。
输入案例:
14 2023
输出案例:
141
代码部分:
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
int a[20];ll dp[20][2][10][10][10][10][2];
ll dfs(int pos,bool limit,bool snt,int p1,int p2,int p3,int p4,int cnt)
{// 修改检测条件为2023和14if ((p1==3 && p2==2 && p3==0 && p4==2) || (p1==4 && p2==1)) cnt=1;if(pos<0)return cnt;if(!limit&&dp[pos][snt][p1][p2][p3][p4][cnt]!=-1)return dp[pos][snt][p1][p2][p3][p4][cnt];ll res=0;int up=limit?a[pos]:9;for(int i=0;i<=up;i++){res+=dfs(pos-1,limit&&(i==up),snt||(i>0),i,p1,p2,p3,cnt);}if(!limit)dp[pos][snt][p1][p2][p3][p4][cnt]=res;return res;
}
ll f(ll x)
{int pos=0;while(x){a[pos++]=x%10;x/=10;}return dfs(pos-1,true,false,0,0,0,0,0);
}
int main()
{memset(dp,-1,sizeof dp);ll a,b;cin>>a>>b;cout<<f(b)-f(a-1)<<"\n";return 0;
}
大家看到这道题肯定有所疑问,上面那道要处理前置0,但是这道并不需要。首先这道题需要找的数字并不是以0开头,所以前置0对结果并没有实质影响。
1.这道题的创新点就在于设置了多个数位来统计前后数字的量。
第三题:这是一道路径问题
问题描述
小蓝有一天误入了一个混境之地。
好消息是:他误打误撞拿到了一张地图,并从中获取到以下信息:
- 混境之地的大小为n⋅m,其中
#
表示不可通过的墙壁,.
表示可以走的路。 - 他现在所在位置的坐标为 (x1,y1) ,而这个混境之地出口的坐标为 (x2,y2) ,当站在出口时即表示可以逃离混境之地。
- 混境之地中存在 26 种恶魔果实(用 A,B,⋯,Z表示),吃下会损失一定能量。吃下苹果 A,B,⋯,Z 分别会导致损失 1,2,⋯,26 点能量。
坏消息是:
- 小蓝太饿了,看到果子就忍不住去吃掉。
- 小蓝仅剩下 E 点能量,能量值不可小于 0 。
小蓝可以往上下左右四个方向行走,不消耗能量。
小蓝想知道他能否逃离这个混境之地,如果可以逃离这里,则输入 Yes
,反之输出 No
。
输入格式
第 1行输入两个正整数 n,m ,表示混境之地的大小。
第 2行输入四个正整数 x1,y1,x2,y2 ,表示小蓝当前所在位置的坐标,以及混境之地出口的坐标。
第 3行至第 n+2行,每行 m 个字符,表示混境之地的地图,其中 #
表示不可通过的墙壁, .
表示普通的道路, A,B,⋯,Z表示恶魔果实。
最后一行一个正整数 E,代表剩余的能量值。
输出格式
输出数据共一行为一个字符串:
- 若小蓝可以逃离混境之地,则输出
Yes
。 - 若小蓝无法逃离混境之地,则输出
No
。
输入案例1:
5 5
1 1 5 5
...#.
..#..
#..CC
...#C
...#.
9
输出案例1:
Yes
输入案例2:
5 5
1 1 5 5
...#.
..#..
#..CC
...#C
...#.
7
输出案例2:
No
代码部分:
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
int a,b,c,dd,n,m,e;
const int N=1010;
char mp[N][N];
int d[N][N];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
void dj()
{priority_queue<pair<int,pair<int,int>>,vector<pair<int,pair<int,int>>>,greater<pair<int,pair<int,int>>>>q;memset(d,0x3f,sizeof d);d[a][b]=0;q.push({0,{a,b}});while(q.size()){int x=q.top().y.x;int y=q.top().y.y;int z=q.top().x;q.pop();for(int i=0;i<4;i++){int nx=x+dx[i],ny=y+dy[i];if(nx<1||nx>n||ny<1||ny>m)continue;if(mp[nx][ny]=='#')continue;int w=(mp[nx][ny]=='.'?0:mp[nx][ny]-'A'+1);if(d[nx][ny]>d[x][y]+w){d[nx][ny]=d[x][y]+w;q.push({d[nx][ny],{nx,ny}});}}}
}
int main()
{cin>>n>>m;cin>>a>>b>>c>>dd;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>mp[i][j];
cin>>e;
dj();
if(e<d[c][dd])cout<<"No";
else cout<<"Yes";return 0;
}
对于这种在方格内有条件限制的问题(传送,有障碍)我们都可以通过这样的方式来求解,也就是方格内的物品会影响能量条,会影响你的前进。
1.用小跟堆堆priority_queue来存放点。
2.根据题意存入w,可能时距离加一,也有可能是判断这里的物品是什么。
3.注意最后要把队列中的东西给pop()掉,不然会陷入死循环。
好了今天的分享就到这里,希望能带给你帮助,希望大家多多关注,后续也将进行新的分享。