AtCoder Beginner Contest 175 比赛人数8820
AtCoder Beginner Contest 175 D Moving Piece 找周期+注意最后一个周期处理(或最后一个非完整周期的处理)
总目录详见https://blog.csdn.net/mrcrack/article/details/104454762
在线测评地址https://atcoder.jp/contests/abc175/tasks/abc175_d
题目大意:当前位置为i,走一步,所达位置为P[i],此步贡献分数为C[i].给定最多可走的步数k,读者可选择走[1,k]之间的任意步,要求分数最多,输出这个最多的分数值。
基本思路:
若有思路,但还有个别数据点无法通过,可以试试提供的这组测试数据:
Input:
2 4
2 1
10 -7
Output:
13
样例模拟如下:
Input:
2 1
2 1
10 -7
Output:
10
走一步情形如下:
位置1出发,到达P[1]=2,分数C[2]=-7
位置2出发,到达P[2]=1,分数C[1]=10
最大值是10
Input:
2 2
2 1
10 -7
Output:
10
走两步情形如下:
位置1出发,第一步,到达P[1]=2,分数C[2]=-7,第二步,到达P[2]=1,分数-7+C[1]=-7+10=3,又回到位置1,位置1的步数周期是2
位置2出发,第一步,到达P[2]=1,分数C[1]=10,第二步,到达P[1]=2,分数10+C[2]=10-7=3,又回到位置1,位置1的步数周期是2
(在走一步,走两步中找最大值)最大值是10
Input:
2 3
2 1
10 -7
Output:
13
走三步情形如下:
位置1出发,第一步,到达P[1]=2,分数C[2]=-7,第二步,到达P[2]=1,分数-7+C[1]=-7+10=3,又回到位置1,位置1的步数周期是2。第三步,到达P[1]=2,分数3+C[2]=3-7=-4
位置2出发,第一步,到达P[2]=1,分数C[1]=10,第二步,到达P[1]=2,分数10+C[2]=10-7=3,又回到位置1,位置1的步数周期是2。第三步,到达P[2]=1,分数3+C[1]=3+10=13
(在走一步,走两步,走三步中找最大值)最大值是13
Input:
2 4
2 1
10 -7
Output:
13
走四步情形如下:
位置1出发,第一步,到达P[1]=2,分数C[2]=-7,第二步,到达P[2]=1,分数-7+C[1]=-7+10=3,又回到位置1,位置1的步数周期是2。第三步,到达P[1]=2,分数3+C[2]=3-7=-4,第四步,到达P[2]=1,分数-4+C[1]=-4+10=6
位置2出发,第一步,到达P[2]=1,分数C[1]=10,第二步,到达P[1]=2,分数10+C[2]=10-7=3,又回到位置1,位置1的步数周期是2。第三步,到达P[2]=1,分数3+C[1]=3+10=13,第二步,到达P[1]=2,分数13+C[2]=13-7=6
(在走一步,走两步,走三步,走四步中找最大值)最大值是13
AC代码如下:
#include <cstdio>
#include <algorithm>
#define LL long long
#define maxn 5010
using namespace std;
LL p[maxn],c[maxn],t[maxn],d[maxn],mid[maxn];//t[i]计算i位置在一个周期内需走的步数,d[i]计算i位置在一个周期内的分数
int main(){
int n,k,i,now,cnt;
LL mx=-1000000000,val;
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)scanf("%lld",&p[i]);
for(i=1;i<=n;i++)scanf("%lld",&c[i]);
for(i=1;i<=n;i++){//计算每个位置对应的周期
now=p[i],d[i]=c[now],t[i]=1,mid[i]=-1000000000,mid[i]=max(d[i],mid[i]);//mid[i]计算i位置一个周期内的最大分数值
while(1){
if(now==i)break;
t[i]++,now=p[now],d[i]+=c[now],mid[i]=max(d[i],mid[i]);
}
}
for(i=1;i<=n;i++){
if(k/t[i]>0){//总步数超过了一个周期
mx=max(mx,mid[i]);//只要总步数超过了一个周期,这条求最值就需用到。
if(k%t[i]==0){mx=max(mx,(k/t[i]-1)*d[i]+mid[i]);continue;}//若总步数是周期的整数倍,这条判断也需用到。
}
val=k/t[i]*d[i];
now=p[i],val+=c[now],mx=max(mx,val),cnt=1;//剩下的步数,凑不成一个周期
while(1){
if(k%t[i]==cnt)break;
cnt++,now=p[now],val+=c[now],mx=max(mx,val);
}
}
printf("%lld\n",mx);
return 0;
}