chacoderのブログ

競技プログラミングそのほか

ABC175D Moving Piece

ABC175Dとりあえず書いてみましたが何ケースかWA。
だいぶ苦労してACしました。

70行弱の自分的には重実装。

最後に気づいたのはサループする場合に余りのところだけでなくループの最後の一周分も回さなければならないところ。

自分でつくったケース
5 10
2 3 4 5 1
10 20 30 40 -90

で100を出力(ただしくは110)して気づきました。

テストケースをつくる能力も磨きたいところです。

バグとり前

#include <bits/stdc++.h>
using namespace std;

long long P[5010];
long long C[5010];

int main() {
  long long N, K;
  cin >> N >> K;
  for (long long i = 1; i <= N; i++) {
        cin >> P[i];
  }
  for (long long i = 1; i <= N; i++) {
        cin >> C[i];
  }
  long long nmax = -1000000000;//各Nについてのmax
  long long ntemp = 0;//各Nについての途中得点
  long long allmax = -1000000000;//全部の最大値
  int flag;
  int cnt;

  //全マスについて最大値を計算する
  for (int i = 1; i <= N; i++) {
    nmax = -1000000000;
    ntemp = 0;
    flag = 1;//サイクルを回ったかどうかのフラグ
    cnt = 1;//サイクルの数 最初の1回は動いてからスタート
    int temp = i;//最初のマスを記録
    int now = temp;//現在のマス
    //最初の移動をする
    now = P[now];
    ntemp+= C[now];
    nmax=max(nmax,ntemp);
    //スタート
    do {
      now = P[now];
      ntemp += C[now];
      nmax = max(nmax, ntemp);
      cnt++;
      if (cnt == K) {
        flag = 0;//サイクルを回らずに終わった場合
        //cout<<"サイクルを回らずに終わった場合"<<endl;
        break;
      }
    }
    while (now != temp);
    //cout<<now<<" "<<cnt<<"flag"<<flag<<"ntemp"<<ntemp<<endl;
    
    //サイクルを回らずに終わった場合
    if (flag != 1) {
      allmax = max(allmax, nmax);
      continue;
    }
    
    //サイクルした場合
      //サイクル後スコアが減少している場合
    if (ntemp <= 0) {
      allmax = max(allmax, nmax);
      //cout<<nmax<<"$"<<allmax<<endl;
      continue;
    }
    
    //サイクル後スコアが増加している場合
    if (ntemp > 0) {
      //cout<<"####"<<endl;
      long long sc = K / cnt;//何サイクル回ったか
      //残りの数を回ったときのMAX
      long long zc = K - sc * cnt;//残り回数を計算
      //long long zanmax = 0;
      ntemp=sc*ntemp;
      for (int j = 0; j < zc; j++) {
        now = P[now];
        ntemp += C[now];
        nmax = max(nmax, ntemp);
      }
      //cout<<nmax<<"*"<<allmax<<endl;
      allmax = max(allmax, nmax);
      continue;
    }
  }
  //cout<<flag<<" "<<cnt<<endl;
  cout << allmax << endl;
  return 0;
}

ACしたコード

#include <bits/stdc++.h>
using namespace std;

long long P[5010];
long long C[5010];

int main() {
  long long N, K;
  cin >> N >> K;
  for (long long i = 1; i <= N; i++) {
        cin >> P[i];
  }
  for (long long i = 1; i <= N; i++) {
        cin >> C[i];
  }
  
  long long nmax = -1000000000;//各Nについてのmax
  long long ntemp = 0;//各Nについての途中得点
  long long allmax = -1000000000;//全部の最大値
  int flag;
  int cnt;

  //全マスについて最大値を計算する
  for (int i = 1; i <= N; i++) {
    nmax = -1000000000;
    ntemp = 0;
    flag = 1;//サイクルを回ったかどうかのフラグ
    cnt = 1;//サイクルの数 最初の1回は動いてからスタート
    int temp = i;//最初のマスを記録
    int now = temp;//現在のマス
    //最初の移動をする
    now = P[now];
    ntemp+= C[now];
    nmax=max(nmax,ntemp);
    //スタート
    do {
      if (cnt == K) {
        flag = 0;//サイクルを回らずに終わった場合
        //cout<<"サイクルを回らずに終わった場合"<<endl;
        break;
      }
      now = P[now];
      ntemp += C[now];
      nmax = max(nmax, ntemp);
      cnt++;

    }
    while (now != temp);
    //cout<<now<<" "<<cnt<<"flag"<<nmax<<"ntemp"<<ntemp<<endl;
    
    //サイクルを回らずに終わった場合
    if (flag != 1) {
      allmax = max(allmax, nmax);
      continue;
    }
    
    //サイクルした場合
      //サイクル後スコアが減少している場合
    if (ntemp <= 0) {
      allmax = max(allmax, nmax);
      //cout<<nmax<<"$"<<allmax<<endl;
      continue;
    }
    
    //サイクル後スコアが増加している場合
    if (ntemp > 0) {
      long long sc = K / cnt;//何サイクル回ったか
      //サイクルを回った余りの数 zc
      long long zc = K - (sc-1) *cnt;//残り回数を計算 1周余計に回す
      ntemp=(sc-1)*ntemp;
      nmax = max(nmax, ntemp);
      //cout<<"sc"<<sc<<"zc"<<zc<<"ntemp"<<ntemp<<endl;
      for (int j = 0; j < zc; j++) {
        now = P[now];
        ntemp += C[now];
        //cout<<i<<"###"<<ntemp<<endl;
        nmax = max(nmax, ntemp);
      }
      //cout<<nmax<<"*"<<allmax<<endl;
      allmax = max(allmax, nmax);
      continue;
    }
  }
  //cout<<flag<<" "<<cnt<<endl;
  cout << allmax << endl;
  return 0;
}