Array Queries CodeForces

Array Queries CodeForces - 797E

题意:给出一个序列a[1],...,a[n](其中数不超过n)和q个查询,对于每个查询(p,k),每次操作将p变为p+a[p]+k,要求对于每个查询输出将p变为大于n的数所需操作数。

WATLERE之路:分析:

很显然的一道dp题,如果p不超过n,则dp[p][k]=dp[p+a[p]+k][k]+1,否则dp[p][k]=0.我有一个想法就是将所有查询按照k排序,然后对相同的k去dp一次,然后输出。

于是我妄想着通过时间O(n^2)的dp把它A掉,然后,我就走上了WATLERE之路.....

第一次,递归,RE

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int ans[100100];
 6 int a[100100];
 7 int n,k,q;
 8 int ans2[100100];//曾经忘记将排序后的查询按原序输出
 9 struct Q
10 {
11     int p,k,num;
12     bool operator<(const Q& b) const
13     {
14         return k<b.k||(k==b.k&&p<b.p);
15     }
16 }q2[100100];
17 int get(int x)
18 {
19     if(ans[x])    return ans[x];
20     if(x>n)
21         return ans[x]=0;
22     else
23         return ans[x]=get(x+a[x]+k)+1;
24 }
25 int main()
26 {
27     int i;
28     scanf("%d",&n);
29     for(i=1;i<=n;i++)
30         scanf("%d",&a[i]);
31     scanf("%d",&q);
32     for(i=1;i<=q;i++)
33     {
34         scanf("%d%d",&q2[i].p,&q2[i].k);
35         q2[i].num=i;
36     }
37     sort(q2+1,q2+q+1);
38     k=q2[1].k;
39     for(i=1;i<=q;i++)
40     {
41         if(q2[i].k!=k)
42         {
43             memset(ans,0,sizeof(ans));
44             k=q2[i].k;
45         }
46         ans2[q2[i].num]=get(q2[i].p);
47     }
48     for(i=1;i<=q;i++)
49         printf("%d
",ans2[i]);
50     return 0;
51 }

第二次,非递归,RE

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int ans[100100],last[100100];
 6 int a[100100];
 7 int n,k,q;
 8 int ans2[100100];//曾经忘记将排序后的查询按原序输出
 9 struct Q
10 {
11     int p,k,num;
12     bool operator<(const Q& b) const
13     {
14         return k<b.k||(k==b.k&&p<b.p);
15     }
16 }q2[100100];
17 int get(int x)
18 {
19     int x1=x;
20     if(ans[x])    return ans[x];
21 //    if(x>n)
22 //        return ans[x]=0;
23 //    else
24 //        return ans[x]=get(x+a[x]+k)+1;
25     while(x<=n)
26     {
27         last[x+a[x]+k]=x;
28         x=x+a[x]+k;
29     }
30     while(x!=x1)
31     {
32         ans[last[x]]=ans[x]+1;
33         x=last[x];
34     }
35     return ans[x];//曾经忘记return
36 }
37 int main()
38 {
39     int i;
40     scanf("%d",&n);
41     for(i=1;i<=n;i++)
42         scanf("%d",&a[i]);
43     scanf("%d",&q);
44     for(i=1;i<=q;i++)
45     {
46         scanf("%d%d",&q2[i].p,&q2[i].k);
47         q2[i].num=i;
48     }
49     sort(q2+1,q2+q+1);
50     k=q2[1].k;
51     for(i=1;i<=q;i++)
52     {
53         if(q2[i].k!=k)
54         {
55             memset(ans,0,sizeof(ans));
56             memset(last,0,sizeof(last));
57             k=q2[i].k;
58         }
59         ans2[q2[i].num]=get(q2[i].p);
60     }
61     for(i=1;i<=q;i++)
62         printf("%d
",ans2[i]);
63     return 0;
64 }

第三次,发现第一、第二次的做法会导致访问超过100000的数组,改掉,TLE

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int ans[500100];
 6 int a[100100];
 7 int n,k,q;
 8 int ans2[500100];//曾经忘记将排序后的查询按原序输出
 9 struct Q
10 {
11     int p,k,num;
12     bool operator<(const Q& b) const
13     {
14         return k<b.k||(k==b.k&&p<b.p);
15     }
16 }q2[100100];
17 int get(int x)
18 {
19     if(ans[x])    return ans[x];
20     if(x>n)
21         return ans[x]=0;
22     else
23         return ans[x]=get(x+a[x]+k)+1;
24 }
25 int main()
26 {
27     int i;
28     scanf("%d",&n);
29     for(i=1;i<=n;i++)
30         scanf("%d",&a[i]);
31     scanf("%d",&q);
32     for(i=1;i<=q;i++)
33     {
34         scanf("%d%d",&q2[i].p,&q2[i].k);
35         q2[i].num=i;
36     }
37     sort(q2+1,q2+q+1);
38     k=q2[1].k;
39     for(i=1;i<=q;i++)
40     {
41         if(q2[i].k!=k)
42         {
43             memset(ans,0,sizeof(ans));
44             k=q2[i].k;
45         }
46         ans2[q2[i].num]=get(q2[i].p);
47     }
48     for(i=1;i<=q;i++)
49         printf("%d
",ans2[i]);
50     return 0;
51 }

至此,我丧失了信仰相信了这是道假dp...

然后,经过查资料,我找到了一种民民是早就想到过的但是却忘了用的方法...

就是将k在500以下的记录下来,500以上的直接算,不记忆化。

然后呢,又有的5次错中错误点:

1.直接算500以上的时候忘记在x>n时返回0 少了if(x>n) return 0;

2.直接算500以上的时候在不是x>n时错误地返回了get2(x+a[x]+k)+1,返回了get2(x+a[x]+k)

AC代码:

 1 #include<cstdio>
 2 int ans[100100][501];
 3 int a[100100];
 4 int k,n,q,p;
 5 int get(int x)
 6 {
 7     if(x>n)
 8         return 0;
 9     if(ans[x][k])    return ans[x][k];
10     return ans[x][k]=get(x+a[x]+k)+1;
11 }
12 int get2(int x)
13 {
14     if(x>n)
15         return 0;
16     else
17         return get2(x+a[x]+k)+1;
18 }
19 int main()
20 {
21     int i;
22     scanf("%d",&n);
23     for(i=1;i<=n;i++)
24         scanf("%d",&a[i]);
25     scanf("%d",&q);
26     for(i=1;i<=q;i++)
27     {
28         scanf("%d%d",&p,&k);
29         if(k<=500)
30             printf("%d
",get(p));
31         else
32             printf("%d
",get2(p));
33     }
34     return 0;
35 }
原文地址:https://www.cnblogs.com/hehe54321/p/cf-797e.html