「美团 CodeM 资格赛」跳格子
题目描述
nnn 个格子排成一列,一开始,你在第一个格子,目标为跳到第 n 个格子。在每个格子 i 里面你可以做出两个选择:
- 选择「a」:向前跳 ai 步。
- 选择「b」:向前跳 bi 步。
把每步的选择写成一个关于字符 a
和 b
的字符串。求到达格子 n 的方案中,字典序最小的字符串。当做出某个选择时,你跳出了这n个格子的范围,则这个选择是不合法的。
- 当没有合法的选择序列时,输出
No solution!
。 - 当字典序最小的字符串无限长时,输出
Infinity!
。 - 否则,输出这个选择字符串。
输入格式
输入有三行。
第一行输入一个整数 n。
第二行输入 n 个整数,分别表示 ai。
第三行输入 n 个整数,分别表示 bi。
输出格式
输出一行字符串表示答案。
样例
样例输入
7
5 -3 6 5 -5 -1 6
-6 1 4 -2 0 -2 0
样例输出
abbbb
数据范围与提示
1≤n≤105
−n≤ai,bi≤n
Solution:
本题主要是贪心加搜索。由于题目中需要输出字典序最小的字符串,所以我们贪心尽可能的走a是肯定没有问题的。于是我们从前往后dfs,尽可能的走a,判断走a后的点能否到达n点,若能到达就标记,当然到达n后就跳出dfs,dfs完后判断n点是否被标记,没被标记就无解,被标记了就再来一次dfs记录路径,同时标记点是否被访问,若一个点被访问两次则说明有环,输出Infinity。否则就输出记录的字符串。
代码:
#include<bits/stdc++.h> #define il inline #define ll long long #define debug pritnf("%d %s\n",__LINE__,__FUNCTION__) using namespace std; const int N=100005; il int gi() { int a=0;char x=getchar();bool f=0; while((x<'0'||x>'9')&&x!='-')x=getchar(); if(x=='-')x=getchar(),f=1; while(x>='0'&&x<='9')a=a*10+x-48,x=getchar(); return f?-a:a; } int n,tot,net[N][2]; char s[N]; bool vis[N],pd[N]; il void dfs(int x) { vis[x]=1; if(x==n){pd[x]=1;return;} for(int i=0;i<=1;i++){ int nx=x+net[x][i]; if(1<=nx&&nx<=n){ if(!vis[nx])dfs(nx); if(pd[nx])pd[x]=1; } } } il void killans(int x) { if(x==n){ for(int i=1;i<=tot;i++)printf("%c",s[i]); exit(0); } if(vis[x]){printf("Infinity!");exit(0);} for(int i=0;i<=1;i++) { int nx=x+net[x][i]; if(1<=nx&&nx<=n){ if(pd[nx])s[++tot]=i+'a',killans(nx); } } } int main() { n=gi(); for(int i=1;i<=n;i++)net[i][0]=gi(); for(int i=1;i<=n;i++)net[i][1]=gi(); dfs(1); if(!pd[1]){printf("No solution!");return 0;} memset(vis,0,sizeof(vis)); killans(1); return 0; }
PS:~蒟蒻写博客不易,转载请注明出处,万分感谢!~