Problem:


Score : 400 points

Problem Statement

Takahashi will play a game using a piece on an array of squares numbered 1, 2, \cdots, N. Square i has an integer C_i written on it. Also, he is given a permutation of 1, 2, \cdots, N: P_1, P_2, \cdots, P_N.

Now, he will choose one square and place the piece on that square. Then, he will make the following move some number of times between 1 and K (inclusive):

In one move, if the piece is now on Square i (1 \leq i \leq N), move it to Square P_i. Here, his score increases by C_{P_i}.

Help him by finding the maximum possible score at the end of the game. (The score is 0 at the beginning of the game.)

Constraints

2 \leq N \leq 5000

1 \leq K \leq 10^9

1 \leq P_i \leq N

P_i \neq i

P_1, P_2, \cdots, P_N are all different.

-10^9 \leq C_i \leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N K
P_1 P_2 \cdots P_N
C_1 C_2 \cdots C_N

Output

Print the maximum possible score at the end of the game.

Sample Input 1

5 2
2 4 5 1 3
3 4 -10 -8 8

Sample Output 1

8

When we start at some square of our choice and make at most two moves, we have the following options:

If we start at Square 1, making one move sends the piece to Square 2, after which the score is 4. Making another move sends the piece to Square 4, after which the score is 4 + (-8) = -4.

If we start at Square 2, making one move sends the piece to Square 4, after which the score is -8. Making another move sends the piece to Square 1, after which the score is -8 + 3 = -5.

If we start at Square 3, making one move sends the piece to Square 5, after which the score is 8. Making another move sends the piece to Square 3, after which the score is 8 + (-10) = -2.

If we start at Square 4, making one move sends the piece to Square 1, after which the score is 3. Making another move sends the piece to Square 2, after which the score is 3 + 4 = 7.

If we start at Square 5, making one move sends the piece to Square 3, after which the score is -10. Making another move sends the piece to Square 5, after which the score is -10 + 8 = -2.

The maximum score achieved is 8.

Sample Input 2

2 3
2 1
10 -7

Sample Output 2

13

Sample Input 3

3 3
3 1 2
-1000 -2000 -3000

Sample Output 3

-1000

We have to make at least one move.

Sample Input 4

10 58
9 1 6 7 8 4 3 2 10 5
695279662 988782657 -119067776 382975538 -151885171 -177220596 -169777795 37619092 389386780 980092719

Sample Output 4

29507023469

The absolute value of the answer may be enormous.



Sample input:
5 2
2 4 5 1 3
3 4 -10 -8 8


Sample output:
8

Submission status: Accepted

Solution code:
N, K = map(int, input().split())
P = list(map(int, input().split()))
C = list(map(int, input().split()))
  
already = [0] * N
A = [-float("inf")] * N

for i in range(N):#スタート地点
  if already[i] == 0:
    already[i] = 1
    q = [i + 1]
    now = i + 1
    score = []
    T = True
    while T:
      now = P[now - 1]
      score.append(C[now - 1])
      if now in q:
        T = False
      else:
        q.append(now)
        already[now - 1] = 1
    
    #A.append(q)
    #S.append(score)
    #print(q)#ループのルート
    #print(score)#ループ中のスコア
    roop = sum(score)
    if len(q) >= K:
      aa = -float("inf")
      for j in range(len(q)):
        time = 0
        bb = 0
        p = j
        while time != K:
          time += 1
          bb += score[p]
          aa = max(aa, bb)
          p += 1
          if p == len(q):
            p = 0
      A[i] = aa      
    else:  
      if roop <= 0:
        aa = -float("inf")
        for j in range(len(q)):
          time = 0
          bb = 0
          p = j
          while time != len(q):
            time += 1
            bb += score[p]
            aa = max(aa, bb)
            p += 1
            if p == len(q):
              p = 0
        A[i] = aa            
      else:
        ll = int(K / len(q)) 
        rr = K % len(q)
        aa = -float("inf")
        for j in range(len(q)):
          time = 0
          bb = ll * roop
          p = j
          while time != len(q):
            time += 1
            bb += score[p]
            if time == rr + 1:
              bb -= roop
            aa = max(aa, bb)
            p += 1
            if p == len(q):
              p = 0
        A[i] = aa           
        

#print(A)      
print(max(A))

Submission status: Accepted

Solution code:
N, K = map(int, input().split())
P = list(map(int, input().split()))
C = list(map(int, input().split()))

seen = []
roots = []
candidates = []

for i in range(N):
    if i+1 in seen:
        continue
    root = [i+1]
    seen.append(i+1)
    to = P[i]
    while(root[0] != to):
        root.append(to)
        seen.append(to)
        to = P[to-1]
    roots.append(root)
for root in roots:
    length = len(root)
    eachMoveBests = [None] * length
    for i in range(length):
        score = 0
        to = P[root[i]-1]
        for j in range(len(root)):
            score += C[to-1]
            to = P[to-1]
            if eachMoveBests[j] == None or score > eachMoveBests[j]:
                eachMoveBests[j] = score
    # 周回スコア
    aroundScore = eachMoveBests[len(eachMoveBests)-1]
    if length < K and aroundScore > 0:
        for i in range(len(eachMoveBests)):
            if K-i-1 % length == 0:
                candidates.append(aroundScore * ((K-i-1) // length))
            else:
                candidates.append(aroundScore * ((K-i-1) // length) + eachMoveBests[i])
    else:
        candidates.append(max(eachMoveBests[:K]))

print(max(candidates))

Submission status: Accepted

Solution code:
n, k = map(int, input().split())
p = list(map(int, input().split()))
c = list(map(int, input().split()))


def get_sum(array):
    score_array = [0]
    for i, a in enumerate(array):
        score_array.append(score_array[i]+a)
    return max(score_array)

def get_max(array, q, mod):
    if q == 0:
        m_score = get_sum(array[:mod])
    else:
        m_score = get_sum(array+array[:mod])
        m_score = sum(array)*(q-1) + m_score
    return m_score

max_score = -float('inf')

for i in range(n):
    score = 0
    score_mv_array = []
    pos = i
    start_pos = p[pos]-1
    for j in range(k):
        pos = p[pos]-1
        if j!=0 and pos == start_pos:
            len_mv = j
            q, mod = divmod(k-j, len_mv)
            score += get_max(score_mv_array, q, mod)
            max_score = max(score, max_score)
            break
        score += c[pos]
        score_mv_array.append(c[pos])
        max_score = max(score, max_score)

print(max_score)

Submission status: Accepted

Solution code:
n, k = map(int, input().split())
p = list(map(int, input().split()))
c = list(map(int, input().split()))

# mv_array = [set() for _ in range(n)]
# score_mv_array = [[] for _ in range(n)]
# score_array = [0]*n

def get_sum(array):
    score_array = [0]
    for i, a in enumerate(array):
        score_array.append(score_array[i]+a)
    return max(score_array)

def get_max(array, q, mod):
    if q == 0:
        m_score = get_sum(array[:mod])
    else:
        m_score = get_sum(array+array[:mod])
        m_score = sum(array)*(q-1) + m_score
    return m_score

max_score = -float('inf')

for i in range(n):
    score = 0
    # max_score = c[i]
    score_mv_array = []
    pos = i
    start_pos = p[pos]-1
    for j in range(k):
        pos = p[pos]-1
        if j!=0 and pos == start_pos:
            # len_mv = len(score_mv_array)
            len_mv = j
            q, mod = divmod(k-j, len_mv)
            score += get_max(score_mv_array, q, mod)
            max_score = max(score, max_score)
            break
        score += c[pos]
        score_mv_array.append(c[pos])
        max_score = max(score, max_score)
    # score_array[i] = max_score

# print(max(score_array))
print(max_score)

Submission status: Accepted

Solution code:
n, k = map(int, input().split())
p = list(map(int, input().split()))
c = list(map(int, input().split()))

# mv_array = [set() for _ in range(n)]
# score_mv_array = [[] for _ in range(n)]
score_array = [0]*n

def get_sum(array):
    score_array = [0]
    for i, a in enumerate(array):
        score_array.append(score_array[i]+a)
    return max(score_array)

def get_max(array, q, mod):
    if q == 0:
        m_score = get_sum(array[:mod])
    else:
        m_score = get_sum(array+array[:mod])
        m_score = sum(array)*(q-1) + m_score
    return m_score

for i in range(n):
    score = 0
    max_score = c[i]
    score_mv_array = []
    pos = i
    start_pos = p[pos]-1
    for j in range(k):
        pos = p[pos]-1
        if j!=0 and pos == start_pos:
            # len_mv = len(score_mv_array)
            len_mv = j
            q, mod = divmod(k-j, len_mv)
            score += get_max(score_mv_array, q, mod)
            max_score = max(score, max_score)
            break
        score += c[pos]
        score_mv_array.append(c[pos])
        max_score = max(score, max_score)
    score_array[i] = max_score

print(max(score_array))

Submission status: Accepted

Solution code:
n, k = map(int, input().split())
p = list(map(int, input().split()))
c = list(map(int, input().split()))

# mv_array = [set() for _ in range(n)]
# score_mv_array = [[] for _ in range(n)]
score_array = [0]*n

def get_sum(array):
    score_array = [0]
    for i, a in enumerate(array):
        score_array.append(score_array[i]+a)
    return max(score_array)

def get_max(array, q, mod):
    if q == 0:
        m_score = get_sum(array[:mod])
    else:
        m_score = get_sum(array+array[:mod])
        m_score = sum(array)*(q-1) + m_score
    return m_score

for i in range(n):
    score = 0
    max_score = c[i]
    score_mv_array = []
    pos = i
    start_pos = p[pos]-1
    for j in range(k):
        pos = p[pos]-1
        if j!=0 and pos == start_pos:
            len_mv = len(score_mv_array)
            # len_mv = j+1
            q, mod = divmod(k-j, len_mv)
            score += get_max(score_mv_array, q, mod)
            max_score = max(score, max_score)
            break
        score += c[pos]
        score_mv_array.append(c[pos])
        max_score = max(score, max_score)
    score_array[i] = max_score

print(max(score_array))

Submission status: Accepted

Solution code:
n, k = map(int, input().split())
p = list(map(int, input().split()))
c = list(map(int, input().split()))

# mv_array = [set() for _ in range(n)]
score_mv_array = [[] for _ in range(n)]
score_array = [0]*n

def get_sum(array):
    score_array = [0]
    for i, a in enumerate(array):
        score_array.append(score_array[i]+a)
    return max(score_array)

def get_max(array, q, mod):
    if q == 0:
        m_score = get_sum(array[:mod])
    else:
        m_score = get_sum(array+array[:mod])
        m_score = sum(array)*(q-1) + m_score
    return m_score

for i in range(n):
    score = 0
    max_score = c[i]
    pos = i
    start_pos = p[pos]-1
    for j in range(k):
        pos = p[pos]-1
        # if pos in mv_array[i]:
        if j!=0 and pos == start_pos:
            len_mv = len(score_mv_array[i])
            q, mod = divmod(k-j, len_mv)
            score += get_max(score_mv_array[i], q, mod)
            max_score = max(score, max_score)
            break
        score += c[pos]
        # mv_array[i].add(pos)
        score_mv_array[i].append(c[pos])
        max_score = max(score, max_score)
    score_array[i] = max_score

print(max(score_array))

Submission status: Accepted

Solution code:
n,k = map(int,input().split())
p = [int(i)-1 for i in input().split()]
c = [int(i) for i in input().split()]

ans = -10**100

for i in range(n):
    chk = [0]*n
    chk[p[i]] = 1
    now = p[i]
    cnt = 1
    val = [-10**100]*n
    val[0] = c[p[i]]
    while 1 == 1:
        if cnt >= k:
            break
        #print(p[now])
        if chk[p[now]] == 1:
            break
        else:
            chk[p[now]] = 1
            val[cnt] = val[cnt-1]+c[p[now]]
            now = p[now]
            cnt += 1
    
    cnt -= 1
    
    #print(val)
    
    if val[cnt] <= 0:
        ans = max(ans,max(val))
    else:
        num = k // (cnt+1)
        amari = k % (cnt+1)
        #print(cnt,k)
        for j in range(cnt+1):
            if j < amari:
                tmp = num*val[cnt]
            else:
                tmp = (num-1)*val[cnt]
            ans = max(ans,tmp+val[j])
            #print(ans,tmp,val[j],j,cnt,num)
    
    #ans = max(ans,max(val))
    
print(ans)

Submission status: Accepted

Solution code:
n, k = map(int, input().split())
p = list(map(int, input().split()))
c = list(map(int, input().split()))

mv_array = [set() for _ in range(n)]
score_mv_array = [[] for _ in range(n)]
score_array = [0]*n

def get_sum(array):
    score_array = [0]
    for i, a in enumerate(array):
        score_array.append(score_array[i]+a)
    return max(score_array)

def get_max(array, q, mod):
    if q == 0:
        m_score = get_sum(array[:mod])
    else:
        m_score = get_sum(array+array[:mod])
        m_score = sum(array)*(q-1) + m_score
    return m_score

for i in range(n):
    score = 0
    max_score = c[i]
    pos = i
    for j in range(k):
        pos = p[pos]-1
        if pos in mv_array[i]:
            len_mv = len(score_mv_array[i])
            q, mod = divmod(k-j, len_mv)
            score += get_max(score_mv_array[i], q, mod)
            max_score = max(score, max_score)
            break
        score += c[pos]
        mv_array[i].add(pos)
        score_mv_array[i].append(c[pos])
        max_score = max(score, max_score)
    score_array[i] = max_score

print(max(score_array))

Submission status: Accepted

Solution code:
#D
class UnionFind():
    # https://www.slideshare.net/chokudai/union-find-49066733
    # 作りたい要素数nで初期化
    # 使用するインスタンス変数の初期化
    def __init__(self, n):
        self.n = n
        # root[x]<0ならそのノードが根かつその値が木の要素数
        # rootノードでその木の要素数を記録する
        # root[x]>=0の場合は、特に直接的な意味を持たない気がする。計算に寄与するので意味はあるのだろうが。
        self.root = [-1]*(n+1)
        # 木をくっつける時にアンバランスにならないように調整する
        # 無結合の時はRank=0,結合して1つ木が深くなると根がRank+=1
        self.rnk = [0]*(n+1)

    # ノードxのrootノードを見つける
    #
    def Find_Root(self, x):
        if(self.root[x] < 0):
            return x
        else:
            # ここで代入しておくことで、後の繰り返しを避ける
            self.root[x] = self.Find_Root(self.root[x])
            return self.root[x]

    # 木の併合、入力は併合したい各ノード
    def Unite(self, x, y):
        # 入力ノードのrootノードを見つける
        x = self.Find_Root(x)
        y = self.Find_Root(y)
        # すでに同じ木に属していた場合
        if(x == y):
            return
        # 違う木に属していた場合rnkを見てくっつける方を決める
        # (1)xのランクの方が大きい(位置が深い)場合
        elif(self.rnk[x] > self.rnk[y]):
            self.root[x] += self.root[y]
            self.root[y] = x

        # (2)yのランクの方が大きい(位置が深い)場合 or 等しい場合
        # また等しい場合、引数の2つめのyの方のランクを1つ増やす
        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            # rnkが同じ（深さに差がない場合）は1増やす
            if(self.rnk[x] == self.rnk[y]):
                self.rnk[y] += 1

    # xとyが同じグループに属するか判断
    # Return: True or False
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)

    # ノードxが属する木のサイズを返す
    def Count(self, x):
        return -self.root[self.Find_Root(x)]
###################################################################    
N,K=map(int,input().split())
UN=UnionFind(N)
P=list(map(int,input().split()))
C=list(map(int,input().split()))
for i,num in enumerate(P):
    UN.Unite(i+1,num)
root=set()
loop_score=dict()
loop_len=dict()

#print(UN.root)
for i,node in enumerate(UN.root):
    if i==0:
        pass
    else:
        if node<0:
            #print(i,"is root")
            root.add(i)
            score=0
            ini=i
            leng=0
            while True:
                ret=P[ini-1]
                score += C[ret-1]
                leng +=1
                if ret==i:
                    break
                else:
                    ini=ret
            loop_score[i]=score
            loop_len[i] = leng
            
#print(loop_score)
#print(loop_len)

ans_list=[]
ans=float("-inf")

for i in range(1,N+1):
    t=K
    p=UN.Find_Root(i)
    
    
    #ループした方がいいかの確認
    if loop_score[p]>0:
        tmp=0
        pos=i
        tmp += ((t//loop_len[p])-1)*loop_score[p]
        if tmp>0:
            ans=max(tmp,ans)
        t = (t%loop_len[p])+loop_len[p]
        for j in range(t):
            pos = P[pos-1]
            tmp += C[pos-1]
            ans=max(tmp,ans)

    else:
        tmp=0
        pos=i
        
        for j in range(min(t,loop_len[p]-1)):
            pos = P[pos-1]
            tmp += C[pos-1]
            ans=max(tmp,ans)
    
print(ans)

Submission status: Accepted

Solution code:
import sys
import math
from collections import defaultdict, deque
from copy import deepcopy
    
input = sys.stdin.readline
def RD(): return input().rstrip()
def F(): return float(input().rstrip())
def I(): return int(input().rstrip())
def MI(): return map(int, input().split())
def MF(): return map(float,input().split())
def LI(): return list(map(int, input().split()))
def LF(): return list(map(float,input().split()))
def Init(H, W, num): return [[num for i in range(W)] for j in range(H)]
def end_of_loop():raise StopIteration

def main():
    N, K = MI()
    P = LI()
    C = LI()
    #1週下再に加算されるスコア並びにあるますから出発した際に１マス進んだ際のスコアがわかればよい。
    #初期化
    ans = []
    result = -float('inf')
    #開始点
    for i in range(N):
        result2= 0
        # start
        temp = i
        d = [-float('inf')] * N
        for j in range(N):
            temp = P[temp]-1
            result2+=C[temp]
            d[j] = result2
            if temp == i:
                index = j+1
                score = result2
                if index < K:
                    amari = K % index
                    syou = K // index
                    if amari !=0:
                        result = max(result, syou*score, syou*score+max(d[0:amari]), (syou-1)*score+max(d[0:index-1]), max(d), (syou-1)*score+max(d[0:index-1]))
                    else:
                        result = max(result, syou*score, max(d), (syou-1)*score+max(d[0:index-1]))
                    break
                else:
                    result = max(result, max(d[0:K]))
                    break
    print(result)

if __name__ == "__main__":
    main()

Submission status: Accepted

Solution code:
n, k = map(int, input().split())
p = list(map(int, input().split()))
c = list(map(int, input().split()))
 
mv_array = [set() for _ in range(n)]
score_mv_array = [[] for _ in range(n)]
score_array = [0]*n
 
def get_sum(array):
    score_array = [0]
    for i, a in enumerate(array):
        score_array.append(score_array[i]+a)
    return max(score_array)
 
def get_max(array, q, mod):
    if q == 0:
        m_score = get_sum(array[:mod])
    else:
        m_score = get_sum(array+array[:mod])
        m_score = sum(array)*(q-1) + m_score
    return m_score
 
 
for i in range(n):
    score = 0
    max_score = c[i]
    pos = i
    for j in range(k):
        pos = p[pos]-1
        if pos in mv_array[i]:
            len_mv = len(score_mv_array[i])
            q, mod = divmod(k-j, len_mv)
            score += get_max(score_mv_array[i], q, mod)
            max_score = max(score, max_score)
            break
        score += c[pos]
        mv_array[i].add(pos)
        score_mv_array[i].append(c[pos])
        max_score = max(score, max_score)
    score_array[i] = max_score
 
print(max(score_array))

Submission status: Accepted

Solution code:
class UnionFind():
    def __init__(self,n):
        self.n=n
        self.root=[-1]*n
        self.rank=[-1]*n

    def Find_Root(self,x):
        if self.root[x]<0:return x
        else:
            self.root[x]=self.Find_Root(self.root[x])
            return self.root[x]

    def Unite(self,x,y):
        x=self.Find_Root(x)
        y=self.Find_Root(y)

        if x==y:return
        elif self.rank[x]>self.rank[y]:
            self.root[x] +=self.root[y]
            self.root[y]=x
        else:
            self.root[y] +=self.root[x]
            self.root[x]=y
            if self.rank[x]==self.rank[y]:
                self.rank[y] +=1

    def isSameGroup(self,x,y):
        return self.Find_Root(x)==self.Find_Root(y)

    def size(self,x):
        return -self.root[self.Find_Root(x)]

    def members(self,x):
        root=self.Find_Root(x)
        return [i for i in range(self.n) if self.Find_Root(i)==root]

    def roots(self):
        return[i for i,j in enumerate(self.root) if j<0]

    def group_members(self):
        return {i:self.members(i) for i in self.roots()}

    def group_count(self):
        return len(self.roots())


N,K=map(int,input().split())
P=list(map(int,input().split()))
C=list(map(int,input().split()))

UnionFind=UnionFind(N+1)
for i in range(N):
    UnionFind.Unite(i+1,P[i])

D=UnionFind.group_members()
E=[]
for i in D:
    A,length=D[i],len(D[i])
    if A[0]==0:continue
    index,F=A[0]-1,[]
    while len(F)!=length:
        index=P[index]-1
        F.append(C[index])
    E.append(F)

ans=-float("inf")
for A in E:
    length=len(A)
    if sum(A)<0:
        A=A*2
        for i in range(length):
            point=0
            for j in range(min(K,length)):
                point +=A[i+j]
                ans=max(ans,point)
    else:
        div,mod=divmod(K,length)
        base=(div-1)*sum(A)
        A=A*3
        for i in range(length):
            point=0
            for j in range(mod+length):
                point +=A[i+j]
                ans=max(ans,base+point)
print(ans)

Submission status: Accepted

Solution code:
class UnionFind():
    def __init__(self,n):
        self.n=n
        self.root=[-1]*n
        self.rank=[-1]*n

    def Find_Root(self,x):
        if self.root[x]<0:return x
        else:
            self.root[x]=self.Find_Root(self.root[x])
            return self.root[x]

    def Unite(self,x,y):
        x=self.Find_Root(x)
        y=self.Find_Root(y)

        if x==y:return
        elif self.rank[x]>self.rank[y]:
            self.root[x] +=self.root[y]
            self.root[y]=x
        else:
            self.root[y] +=self.root[x]
            self.root[x]=y
            if self.rank[x]==self.rank[y]:
                self.rank[y] +=1

    def isSameGroup(self,x,y):
        return self.Find_Root(x)==self.Find_Root(y)

    def size(self,x):
        return -self.root[self.Find_Root(x)]

    def members(self,x):
        root=self.Find_Root(x)
        return [i for i in range(self.n) if self.Find_Root(i)==root]

    def roots(self):
        return[i for i,j in enumerate(self.root) if j<0]

    def group_members(self):
        return {i:self.members(i) for i in self.roots()}

    def group_count(self):
        return len(self.roots())


N,K=map(int,input().split())
P=list(map(int,input().split()))
C=list(map(int,input().split()))

UnionFind=UnionFind(N+1)
for i in range(N):
    UnionFind.Unite(i+1,P[i])

D=UnionFind.group_members()
E=[]
for i in D:
    A,length=D[i],len(D[i])
    if A[0]==0:continue
    index,F=A[0]-1,[]
    while len(F)!=length:
        index=P[index]-1
        F.append(C[index])
    E.append(F)

ans=-float("inf")
for A in E:
    length=len(A)
    if sum(A)<0:
        A=A*2
        for i in range(length):
            point=0
            for j in range(min(K,length)):
                point +=A[i+j]
                ans=max(ans,point)
    else:
        div,mod=divmod(K,length)
        base=(div-1)*sum(A)
        A=A*3
        for i in range(length):
            point=0
            ans=max(ans,base)
            for j in range(mod+length):
                point +=A[i+j]
                ans=max(ans,base+point)
print(ans)

Submission status: Accepted

Solution code:
n,k = map(int,input().split())
p = [int(i)-1 for i in input().split()]
c = [int(i) for i in input().split()]
INF = float("INF")
ans = -INF

for si in range(n):
    x = si
    S = []
    tot = 0
    while True:
        x = p[x]
        S.append(c[x])
        tot += c[x]
        if x == si: break
    l = len(S)
    t = 0
    for i in range(l):
        if i+1 > k: break
        t += S[i]
        now = t
        if tot > 0:
            e = (k-(i+1))//l
            now += tot*e
        ans = max(ans, now)
print(ans)

Submission status: Accepted

Solution code:

n, k = map(int, input().split())
p = [int(x) - 1 for x in input().split()]
c = [int(x) for x in input().split()]
pow_num = 31
point = [[0] * n for i in range(pow_num)]
point_max = [[0] * n for i in range(pow_num)]
posi = [[0] * n for i in range(pow_num)]

c_set = set(c)
if all([i < 0 for i in c_set]):
    print(max(c_set))
else:
    for i in range(pow_num):
        if i == 0:
            for j in range(n):
                posi[i][j] = p[j]
                point[i][j] = c[p[j]]
            continue
        for j in range(n):
            posi[i][j] = posi[i-1][posi[i-1][j]]
            point[i][j] = point[i-1][j] + point[i-1][posi[i-1][j]]
    for i in range(pow_num):
        if i == 0:
            for j in range(n):
                point_max[i][j] = point[i][j]
            continue
        for j in range(n):
            point_max[i][j] = max(point_max[i-1][j], \
                point[i-1][j] + point_max[i-1][posi[i-1][j]])

    power_count = list()
    for i in range(pow_num):
        if k & (1 << i):
            power_count.append(i)

        ans = 0
        for i in range(n):
            next_posi = i
            cumsum_point = 0
            for posi_idx in power_count:
                if ans < cumsum_point + point_max[posi_idx][next_posi]:
                    ans = cumsum_point + point_max[posi_idx][next_posi]
                cumsum_point += point[posi_idx][next_posi]
                next_posi = posi[posi_idx][next_posi]

    print(ans)

Submission status: Accepted

Solution code:
# -*- coding: utf-8 -*-
import sys
sys.setrecursionlimit(10**9)
N, K = map(int, input().split())
Ps = list(map(int, input().split()))
Cs = list(map(int, input().split()))
max_list = list()
for i in range(N):
    next = Ps[i] - 1
    scores = [Cs[next]]
    while next != i:
        next = Ps[next] - 1
        scores.append(scores[-1] + Cs[next])
    l = len(scores)
    if K <= l:
        max_list.append(max(scores[:K]))
    else:
        if scores[-1] < 0:
            max_list.append(max(scores))
        else:
            a, b = divmod(K, l)
            cand1 = 0
            if b!=0:
                cand1 = a*scores[-1] + max(scores[:b])
            cand2 = (a-1)*scores[-1] + max(scores)
            max_list.append(max(cand1, cand2))
    #print(scores)
print(max(max_list))

Submission status: Accepted

Solution code:
n, k = map(int, input().split())
p = list(map(int, input().split(" ")))
for i in range(n):
    p[i] -= 1
c = list(map(int, input().split(" ")))
ans = -10000000000
for start in range(n):
    now = start
    pt = 0
    cycle = 0
    looplen = 0

    while 1:
        now = p[now]
        pt += c[now]
        looplen += 1
        if now == start:
            break

    cycle = pt
    pt = 0
    for i in range(looplen):
        now = p[now]
        pt += c[now]
        aftermove = k - i-1
        if aftermove < 0:
            continue

        loop = aftermove//looplen
        ans = max(ans, pt)
        ans = max(ans, pt+loop*cycle)
print(ans)

Submission status: Accepted

Solution code:

def resolve():
    INF = 10 ** 18
    N, K = map(int, input().split())
    P = list(map(lambda x: int(x) - 1, input().split()))
    C = list(map(int, input().split()))

    ans = -INF
    for s in range(N):
        S = []
        x = P[s]
        S.append(C[x])
        tot = C[x]
        while s != x:  # スタート位置に戻ったら終了
            x = P[x]
            S.append(C[x])
            tot += C[x]
        s_n = len(S)
        t = 0
        for i in range(s_n):
            t += S[i]
            now = t
            if tot > 0:
                loop = (K - i - 1) // s_n
                now += tot * loop
            ans = max(ans, now)

    print(ans)


if __name__ == "__main__":
    resolve()

Submission status: Accepted

Solution code:
n,k=map(int,input().split())
p=list(map(int,input().split()))
c=list(map(int,input().split()))

ans=float('inf')*-1

for i in range(n):
    visited=[i]
    pin=0
    now=i
    for j in range(k):
        now=p[now]-1
        pin+=c[now]
        ans=max(ans,pin)
        visited+=[now]

        if visited[0]==visited[-1]:
            if pin>0:
                pin*=(k//(len(visited)-1)-1)
                ans=max(ans,pin)

                for s in range(k%(len(visited)-1)+len(visited)-1):
                    now=p[now]-1
                    pin+=c[now]
                    ans=max(ans,pin)

                break

            else:
                break

print(ans)

Submission status: Accepted

Solution code:
N,K = map(int,input().split())
P = list(map(int,input().split()))
C = list(map(int,input().split()))

LC = [-1] * N
# Pが順列なので，結局それぞれのマスはループのどれかにいる事がわかる．あとは，ループの長さとループ1回分のコスト(a->a)を計算しておく
# ループ1回分のコストが正の場合はループをなるべく回す．負の場合は1回もループしないほうがいい．ただし最初のa->aは考慮する.
# 1回は最低でも動かないといけないから
max_score = -float('inf')
for i in range(N):
    Loop_len = 0
    Loop_cost =[]
    Loop_cost_sum = 0
    now = i
    while True:
        now = P[now] - 1
        Loop_len += 1
        Loop_cost_sum += C[now]
        Loop_cost.append(Loop_cost_sum)
        if now == i:
            break
    # それぞれのマスへのループによるコストのゲインと,最短でそこへいくまでの移動コストを計算してコストを決定する
    for i,lc in enumerate(Loop_cost):
        if K-(i+1)<0: # 行けないので
            continue
        possible_loop_num = (K-(i+1))//Loop_len
        cost = lc + max(0,Loop_cost_sum) * possible_loop_num
        max_score = max(cost,max_score)

print(max_score)

Submission status: Accepted

Solution code:
def main():
    cells, can_jump = [int(x) for x in input().split()]
    jumps_from = [int(x) - 1 for x in input().split()]
    score_on = [int(x) for x in input().split()]

    ans = - 10**10
    for start in range(cells):
        route = []
        position = start
        while True:
            route.append(score_on[position])
            position = jumps_from[position]
            if position == start:  # Looped
                break

        length = len(route)
        total = sum(route)
        accum = 0
        for jumping, score in enumerate(route):
            jumping += 1
            accum += score
            if jumping > can_jump:
                break
            candidate = accum
            if total > 0:
                candidate += total * ((can_jump - jumping) // length)
            ans = max(ans, candidate)
    return ans


if __name__ == '__main__':
    ans = main()
    print(ans)

Submission status: Accepted

Solution code:
def main():
    cells, can_jump = [int(x) for x in input().split()]
    jumps_from = [int(x) - 1 for x in input().split()]
    score_on = [int(x) for x in input().split()]

    ans = - 10**10
    for start in range(cells):
        route = []
        position = start
        while True:
            route.append(score_on[position])
            position = jumps_from[position]
            if position == start:  # Looped
                break

        length = len(route)
        total = sum(route)
        accum_tmp = 0
        for jumping, score in enumerate(route):
            accum_tmp += score
            if jumping + 1 > can_jump:
                break
            accum = accum_tmp
            if total > 0:
                accum += total * ((can_jump - (jumping + 1)) // length)
            ans = max(ans, accum)
    return ans


if __name__ == '__main__':
    ans = main()
    print(ans)