アルゴリズム実装と最適化テクニック

問題B:完全立方数を避ける数列選択

数列 $\{a_n\}$ から部分集合を選び、任意の2要素の積が完全立方数とならないようにする。$n\le 10^5$、$1\le a_i\le 10^{10}$。

重要な観察:$10^5$ より大きい素因数を持つ数は常に解答に寄与する。その他の数については、非1の完全立方因子をすべて除去してから処理する。


ll factorizeRandom(ll val) {
    if (val % 2 == 0) return 2;
    ll diff, ptr1, ptr2, param;
    while (true) {
        diff = 1;
        for (int step = 1; step <= 256; step <<= 1) {
            ptr1 = ptr2 = 0;
            param = rng() % (val - 1) + 1;
            for (int iter = 1; iter <= step; iter++) {
                ptr1 = iterate(iterate(ptr1, param, val), param, val);
                ptr2 = iterate(ptr2, param, val);
                diff = multiply(diff, abs(ptr1 - ptr2), val);
            }
            ll g = __gcd(diff, val);
            if (g != 1) return g;
        }
    }
}

Pollard-Rhoアルゴリズムの実装例。ランダムシードの選択が重要で、233では一部のテストケースでTLEを発生させる。

問題C:オンライン文字列照合

文字列 $s$ と複数のクエリ文字列 $t$ が与えられる。各クエリについて、$t$ が $s$ 中に出現する回数を答える。オンラインで処理する必要がある。

$|s|, q, |t|, \sum |t| \le 10^5$、$|\Sigma|=10^6$。

解法戦略:クエリ長で分割し、短いものはKMP、長いものはハッシュを使用する。全体の計算量は $O(n\sqrt{n}\log n)$ に抑えられる。


void buildHash() {
    powBase[0] = 1;
    for (int i = 1; i <= MAXLEN; i++) 
        powBase[i] = powBase[i-1] * HASH_BASE;
    for (int i = 1; i <= ALPHABET_SIZE; i++) 
        charHash[i] = rng();
}

int queryKMP(int qlen, vector<int>& pattern, vector<int>& text) {
    vector<int> combined(qlen + text.size() + 1);
    for (int i = 0; i < qlen; i++) combined[i] = pattern[i];
    combined[qlen] = -1;
    for (int i = 0; i < text.size(); i++) combined[qlen + 1 + i] = text[i];
    
    vector<int> fail(combined.size(), 0);
    for (int i = 1; i < combined.size(); i++) {
        int j = fail[i-1];
        while (j > 0 && combined[i] != combined[j]) j = fail[j-1];
        if (combined[i] == combined[j]) j++;
        fail[i] = j;
    }
    
    int count = 0;
    for (int i = qlen + 1; i < combined.size(); i++) {
        if (fail[i] == qlen) count++;
    }
    return count;
}

問題D:最適化部分列問題

2つの排列 $S$ と $G$(長さ $n$)と整数 $k$ が与えられる。$i \in [n-k+1, n]$ に対して、$G[i:n]$ をランダムに並び替えられる。この操作で、ある部分列 $S[x:y]$ を並び替えたものが $G[l:r]$ と一致するような区間 $[l,r]$ の数を最大化する。

$k \le n \le 2\times10^5$。

この問題では、排列の局所的な再配置がグローバルなパターンマッチングにどう影響するかを分析する必要がある。

タグ: Pollard-Rho 文字列照合 アルゴリズム 実装技術 最適化

5月19日 21:29 投稿