AtCoder Beginner Contest 175 D Moving Piece 找周期+注意最后一个周期处理(或最后一个非完整周期的处理)

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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值