Cow Program CodeForces - 283B
考察:记忆化搜索
错误思路1:
数组记录x与y的值,如果重复出现就判死循环.
审题,只有当x的值与操作在此前出现过才是死循环,y的值不影响循环,而单凭x的值也不能判死循环.因为可能进行的操作会不同.所以根据x与下一个操作才能判定一个状态.
错误思路2:
for循环i-1遍,用bool数组记录是否出现过此操作,如果出现过就是死循环.没有就继续模拟,条件达成就输出模拟后的y值.每次模拟都对bool数组清零.
TLE,每次memset 2*105超时.
正确思路:
错误思路2不看时间是正确的答案,因此我们需要优化减少时间.可以发现,在一个数组中,即时x+i的起始值不同,如果在某次操作后得到的x值相同,那么往后y的增量全部都相同.可以考虑记录x j操作后y的增量.并且即使x+i起始值不同,如果到某处x 与操作相同,而已知此后会死循环,我们也可以直接退出.
因此大体思路是:用f[x][j]数组记录x进行j操作后y的增量.dfs完后利用回溯累加.(一定不要记录最后的结果y值,因为起始值不同y值不同).但是还需要一个数组记录此操作是否出现过,上面的f数组配合st数组才能完成判循环的功能.
直接记录增量是不能完成死循环功能的,因为会破坏原来的值.
注意:记得long long
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 typedef long long ll; 7 const int N = 200010; 8 ll f[N][2];//表示当前数x进行j操作时,会得到的y值. 9 int a[N],n; 10 bool st[N][2]; 11 void dfs(ll x,int j) 12 { 13 if(f[x][j]!=-1) return; 14 if(st[x][j]) return; 15 st[x][j] = 1; 16 ll t = j?x+a[x]:x-a[x]; 17 if(t<=0||t>n) f[x][j] = a[x]; 18 else{ 19 dfs(t,j^1); 20 if(f[t][j^1]!=-1) f[x][j] = f[t][j^1]+a[x]; 21 } 22 } 23 int main() 24 { 25 scanf("%d",&n); 26 memset(f,-1,sizeof f); 27 for(int i=2;i<=n;i++) scanf("%d",&a[i]); 28 for(int i=1;i<n;i++) 29 { 30 dfs(1+i,0); 31 printf("%lld\n",f[i+1][0]==-1?-1:f[i+1][0]+i); 32 } 33 return 0; 34 }