Submission #15793676


Source Code Expand

#include <iostream>
#include <algorithm>
#include <vector>
#include <array>
#include <string>

struct Trie {
    struct Node {
        int c;
        std::array<int, 26> nxt;  // 子のindex
        std::array<int, 26> cnt;  // 文字cを含むような子孫の数
        int sz;                   // 部分木のサイズ

        Node(int c) : c(c), sz(0) {
            nxt.fill(-1);
            cnt.fill(0);
        }
    };

    std::vector<Node> nodes;

    Trie() { nodes.emplace_back(-1); }

    void add(const std::string& s) {
        int pos = 0;
        for (char c : s) {
            int ci = c - 'a';

            int npos = nodes[pos].nxt[ci];
            if (npos == -1) {
                npos = nodes.size();
                nodes[pos].nxt[ci] = npos;
                nodes.emplace_back(ci);
            }
            pos = npos;
        }

        ++nodes[pos].sz;
    }

    int find(const std::string& s) const {
        int pos = 0;
        for (char c : s) {
            int ci = c - 'a';
            pos = nodes[pos].nxt[ci];
        }
        return pos;
    }

    // cntを埋める
    void fillcnt() {
        for (int pos = (int)nodes.size() - 1; pos >= 0; --pos) {
            auto& node = nodes[pos];

            for (int c = 0; c < 26; ++c) {
                int npos = node.nxt[c];
                if (npos == -1) continue;

                const auto& cnode = nodes[npos];
                node.sz += cnode.sz;
                for (int d = 0; d < 26; ++d) {
                    node.cnt[d] += cnode.cnt[d];
                }
            }

            // 全ての子孫はcを含む
            if (node.c != -1) node.cnt[node.c] = node.sz;
        }
    }
};

using lint = long long;

void solve() {
    int n;
    std::cin >> n;

    std::vector<std::string> ss(n);
    for (auto& s : ss) {
        std::cin >> s;
        std::reverse(s.begin(), s.end());
    }

    Trie trie;
    for (const auto& s : ss) trie.add(s);

    trie.fillcnt();

    lint ans = 0;

    for (auto s : ss) {
        // 末尾とそれ以外に分離
        int last = s.back() - 'a';
        s.pop_back();

        int pos = trie.find(s);

        // posの子でlastを含むものを数え上げ
        for (int ci = 0; ci < 26; ++ci) {
            int npos = trie.nodes[pos].nxt[ci];

            if (npos == -1) continue;
            ans += trie.nodes[npos].cnt[last];

            // 自分自身は除く
            if (ci == last) --ans;
        }
    }

    std::cout << ans << "\n";
}

int main() {
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);

    solve();

    return 0;
}

Submission Info

Submission Time
Task B - First Second
User Tiramister
Language C++ (GCC 9.2.1)
Score 700
Code Size 2622 Byte
Status AC
Exec Time 402 ms
Memory 227984 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 700 / 700
Status
AC × 2
AC × 26
Set Name Test Cases
Sample s1.txt, s2.txt
All 001.txt, 002.txt, 003.txt, 004.txt, 005.txt, 006.txt, 007.txt, 008.txt, 009.txt, 010.txt, 011.txt, 012.txt, 013.txt, 014.txt, 015.txt, 016.txt, 017.txt, 018.txt, 019.txt, 020.txt, 021.txt, 022.txt, 023.txt, 024.txt, s1.txt, s2.txt
Case Name Status Exec Time Memory
001.txt AC 5 ms 3444 KiB
002.txt AC 2 ms 3568 KiB
003.txt AC 2 ms 3564 KiB
004.txt AC 21 ms 10404 KiB
005.txt AC 135 ms 61104 KiB
006.txt AC 394 ms 226400 KiB
007.txt AC 353 ms 227984 KiB
008.txt AC 240 ms 120164 KiB
009.txt AC 118 ms 62404 KiB
010.txt AC 402 ms 226268 KiB
011.txt AC 395 ms 225532 KiB
012.txt AC 152 ms 115168 KiB
013.txt AC 207 ms 115440 KiB
014.txt AC 295 ms 225432 KiB
015.txt AC 79 ms 32192 KiB
016.txt AC 33 ms 8004 KiB
017.txt AC 18 ms 6240 KiB
018.txt AC 27 ms 7960 KiB
019.txt AC 24 ms 8016 KiB
020.txt AC 246 ms 118316 KiB
021.txt AC 313 ms 227072 KiB
022.txt AC 341 ms 225888 KiB
023.txt AC 331 ms 225624 KiB
024.txt AC 397 ms 225716 KiB
s1.txt AC 3 ms 3604 KiB
s2.txt AC 5 ms 3444 KiB