結果
| 問題 |
No.464 PPAP
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2016-12-15 23:18:19 |
| 言語 | C++11(廃止可能性あり) (gcc 13.3.0) |
| 結果 |
AC
|
| 実行時間 | 478 ms / 2,000 ms |
| コード長 | 3,802 bytes |
| コンパイル時間 | 963 ms |
| コンパイル使用メモリ | 73,448 KB |
| 実行使用メモリ | 70,912 KB |
| 最終ジャッジ日時 | 2024-11-30 08:59:38 |
| 合計ジャッジ時間 | 4,758 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 22 |
ソースコード
#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#define REP(i,s,n) for(int i=(int)(s);i<(int)(n);i++)
using namespace std;
typedef long long int ll;
typedef vector<int> VI;
typedef vector<ll> VL;
typedef pair<int, int> PI;
const ll mod = 1e9 + 7;
/*
* Suffix Array.
* Required Headers: algorithm, cassert, string, vector
* Verified by: http://arc050.contest.atcoder.jp/submissions/818745
* Reference: http://mayokoex.hatenablog.com/entry/2016/04/03/145845
*/
struct compare_sa {
const std::vector<int> &rank;
int n, k;
compare_sa(const std::vector<int> &rank, int n, int k) : rank(rank), n(n), k(k) {}
bool operator () (int i, int j) {
if (rank[i] != rank[j]) {
return rank[i] < rank[j];
}
int ri = i + k <= n ? rank[i + k] : -1;
int rj = j + k <= n ? rank[j + k] : -1;
return ri < rj;
}
};
std::vector<int> create_sa(const std::string& s) {
int n = s.length();
std::vector<int> sa(n + 1, -1);
std::vector<int> rank(n + 1, -1);
std::vector<int> tmp(n + 1, -1);
for (int i = 0; i <= n; ++i) {
sa[i] = i;
rank[i] = i < n ? s[i] : -1;
}
for (int k = 1; k <= n; k *= 2) {
compare_sa cp = compare_sa(rank, n, k);
std::sort(sa.begin(), sa.begin() + n + 1, cp);
tmp[sa[0]] = 0;
for (int i = 1; i <= n; ++i) {
tmp[sa[i]] = tmp[sa[i - 1]] + (cp(sa[i - 1], sa[i]) ? 1 : 0);
}
for (int i = 0; i <= n; ++i) {
rank[i] = tmp[i];
}
}
return sa;
}
std::vector<int> create_lcp(const std::string &s, const std::vector<int> &sa) {
int n = s.length();
std::vector<int> rank(n + 1);
std::vector<int> lcp(n, -1);
for (int i = 0; i <= n; ++i) {
rank[sa[i]] = i;
}
int h = 0;
lcp[0] = 0;
for (int i = 0; i < n; ++i) {
int j = sa[rank[i] - 1];
h = std::max(0, h - 1);
for (; j + h < n && i + h < n; ++h) {
if (s[j + h] != s[i + h]) {
break;
}
}
lcp[rank[i] - 1] = h;
}
return lcp;
}
std::vector<std::vector<int> > create_sparse_table(int n, const std::vector<int> &lcp) {
int h = 1;
while ((1 << h) < n) {
++h;
}
std::vector<std::vector<int> > st(h + 1, std::vector<int>(n));
for (int i = 0; i < n; ++i) {
st[0][i] = lcp[i];
}
for (int j = 1; j <= h; ++j) {
for (int i = 0; i <= n - (1 << j); ++i) {
st[j][i] = std::min(st[j - 1][i], st[j - 1][i + (1 << (j-1))]);
}
}
return st;
}
int top_bit(int t) {
for (int i = 31; i >= 0; --i) {
if ((1 << i) & t) {
return i;
}
}
assert (0);
}
int get_lcp(const std::vector<std::vector<int> > &st, int f, int s) {
if (f > s) {
std::swap(f, s);
}
assert (f < s);
int diff = top_bit(s - f);
return std::min(st[diff][f], st[diff][s - (1 << diff)]);
}
const int N = 5001;
int pal[N][N];
int pal2[N];
int main(void){
string s;
cin >> s;
string s_rev = s;
reverse(s_rev.begin(), s_rev.end());
int n = s.length();
string t = s + "$" + s_rev;
VI sa = create_sa(t);
VI sa_inv(sa.size());
REP(i, 0, sa.size()) {
sa_inv[sa[i]] = i;
}
VI lcp = create_lcp(t, sa);
vector<VI> spt = create_sparse_table(2 * n + 1, lcp);
REP(i, 0, n) {
REP(j, i, n) {
int idx1 = sa_inv[i];
int idx2 = sa_inv[n + 1 + (n - 1 - j)];
int comm_len = get_lcp(spt, idx1, idx2);
if (0) {
cerr << "idx1=" << idx1 << ", idx2=" << idx2 << endl;
cerr << "lcp(s[" << i << "..], s[.." << j << "].rev) = "
<< comm_len;
if (comm_len >= j - i + 1) {
cerr << " pal";
}
cerr << endl;
}
pal[i][j] = comm_len >= j - i + 1;
}
}
REP(i, 0, n) {
REP(j, 0, n) {
pal2[j] += pal[0][i] * pal[i + 1][j];
}
}
ll tot = 0;
REP(i, 0, n) {
REP(j, i + 2, n) {
tot += (ll)pal2[i] * pal[j][n - 1];
}
}
cout << tot << endl;
}