結果

問題 No.465 PPPPPPPPPPPPPPPPAPPPPPPPP
ユーザー rickythetarickytheta
提出日時 2016-12-16 23:23:40
言語 C++11
(gcc 11.4.0)
結果
AC  
実行時間 124 ms / 2,000 ms
コード長 3,616 bytes
コンパイル時間 2,018 ms
コンパイル使用メモリ 152,804 KB
実行使用メモリ 22,376 KB
最終ジャッジ日時 2023-08-20 18:07:24
合計ジャッジ時間 3,921 ms
ジャッジサーバーID
(参考情報)
judge11 / judge14
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 3 ms
9,800 KB
testcase_01 AC 3 ms
9,712 KB
testcase_02 AC 3 ms
9,936 KB
testcase_03 AC 3 ms
9,708 KB
testcase_04 AC 3 ms
9,764 KB
testcase_05 AC 9 ms
11,280 KB
testcase_06 AC 33 ms
22,248 KB
testcase_07 AC 12 ms
11,300 KB
testcase_08 AC 44 ms
22,084 KB
testcase_09 AC 54 ms
21,456 KB
testcase_10 AC 53 ms
21,576 KB
testcase_11 AC 124 ms
22,156 KB
testcase_12 AC 94 ms
20,904 KB
testcase_13 AC 58 ms
20,216 KB
testcase_14 AC 91 ms
22,376 KB
testcase_15 AC 43 ms
20,228 KB
testcase_16 AC 48 ms
20,104 KB
testcase_17 AC 48 ms
20,248 KB
testcase_18 AC 48 ms
22,228 KB
testcase_19 AC 49 ms
18,208 KB
testcase_20 AC 44 ms
21,592 KB
testcase_21 AC 69 ms
22,312 KB
32_ratsliveonnoevilstar.txt AC 43 ms
18,148 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

typedef int _loop_int;
#define REP(i,n) for(_loop_int i=0;i<(_loop_int)(n);++i)
#define FOR(i,a,b) for(_loop_int i=(_loop_int)(a);i<(_loop_int)(b);++i)
#define FORR(i,a,b) for(_loop_int i=(_loop_int)(b)-1;i>=(_loop_int)(a);--i)

#define DEBUG(x) cout<<#x<<": "<<x<<endl
#define DEBUG_VEC(v) cout<<#v<<":";REP(i,v.size())cout<<" "<<v[i];cout<<endl
#define ALL(a) (a).begin(),(a).end()

#define CHMIN(a,b) a=min((a),(b))
#define CHMAX(a,b) a=max((a),(b))

// mod
const ll MOD = 1000000007ll;
#define FIX(a) ((a)%MOD+MOD)%MOD

// floating
typedef double Real;
const Real EPS = 1e-11;
#define EQ0(x) (abs(x)<EPS)
#define EQ(a,b) (abs(a-b)<EPS)
typedef complex<Real> P;

int n;
char s[525252];

// manacher
int m;
char ss[1252525];
int mana[1252525];
ll tailpal[525252];
inline bool pal(int l,int r){
  return mana[r+l-1] > r-l-1;
}

ll pl[525252];
ll gpl[525252];

int main(){
  scanf("%s",s);
  n = strlen(s);
  for(int i=0;i<n;i++){
    ss[2*i] = s[i];
    ss[2*i+1] = '$';
  }
  m = 2*n-1;
  // manacher
  {
    int i=0,j=0;
    while(i<m){
      while(i-j>=0 && i+j<m && ss[i-j]==ss[i+j])j++;
      mana[i] = j;
      int k=1;
      while(i-k>=0 && i+k<m && k+mana[i-k]<j){
        mana[i+k] = mana[i-k];
        k++;
      }
      i += k;
      j -= k;
    }
  }
  for(int i=n-1;i>0;i--){
    tailpal[i-1] = tailpal[i] + (mana[n+i-1]>n-i-1);
  }
  // 解説を読みました……><
  // https://arxiv.org/pdf/1403.2431v2.pdf
  // pp.11
  typedef pair<int,pii> trip;
  #define X first
  #define Y second.first
  #define Z second.second
  #define PACK(x,y,z) trip(x,pii(y,z))
  #define UNPACK(x,y,z,t) int x=(t).X,y=(t).Y,z=(t).Z
  vector<trip> G,G2;
  FOR(j,1,n+1){
    G2.clear();
    for(auto T:G){
      UNPACK(x,y,z,T);
      // palindrome
      if(x>1 && s[x-2]==s[j-1]){
        G2.push_back(PACK(x-1,y,z));
      }
    }
    swap(G,G2);
    G2.clear();
    int r = -j;
    for(auto T:G){
      UNPACK(x,y,z,T);
      if(x-r != y){
        G2.push_back(PACK(x,x-r,1));
        if(z>1){
          G2.push_back(PACK(x+y,y,z-1));
        }
      }else{
        G2.push_back(T);
      }
      r = x + (z-1)*y;
    }
    if(j>1 && s[j-2]==s[j-1]){
      G2.push_back(PACK(j-1,j-1-r,1));
      r = j-1;
    }
    G2.push_back(PACK(j,j-r,1));
    G.clear();
    auto fst = G2[0];
    UNPACK(xx,yy,zz,fst);
    bool flag = true;
    for(auto T:G2){
      if(flag){
        flag=false;
        continue;
      }
      UNPACK(x,y,z,T);
      if(y==yy){
        zz += z;
      }else{
        G.push_back(PACK(xx,yy,zz));
        xx = x;
        yy = y;
        zz = z;
      }
    }
    G.push_back(PACK(xx,yy,zz));
    // modify for split palindrome
    // 元 : prefixを最小のpalindromeで構成する 数:pl[i]
    // 新 : PPと分解する数
    // 周期性のあるpalindromeで表せるため計算が使いまわせる、らしい

    // pl[j] = j;
    pl[j-1] = 0;
    for(auto T:G){
      UNPACK(x,y,z,T);
      r = x + (z-1)*y;
      // int mm = pl[r-1]+1;
      // 最小周期でPPと分割
      ll mm = 0;
      if(r>=2 && pal(0,r-2+1))mm = 1;
      // 周期1つ戻した計算結果を再利用
      if(z>1){
        // CHMIN(mm,gpl[x-z]);
        mm += gpl[x-y];
      }
      // メモ
      if(y<=x){
        gpl[x-y] = mm;
      }
      // CHMIN(pl[j],mm);
      pl[j-1] += mm;
    }
  }

  ll ans = 0;
  FOR(i,1,n-1){
    ans += pl[i] * tailpal[i+1];
  }
  printf("%lld\n",ans);

  // 難しい><
  return 0;
}
0