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 }

 

posted @ 2021-02-18 18:39  acmloser  阅读(90)  评论(0编辑  收藏  举报