Submission #622281

#TimeUsernameProblemLanguageResultExecution timeMemory
622281jophyyjhLottery (CEOI18_lot)C++14
65 / 100
78 ms21376 KiB
/**
 * Notes during contest.
 * 
 * ------ A ------
 * Looks like a dp.
 * 
 * ------ B ------
 * I think i've seen sth similar on luogu. First, let's assume that d >= 0 and i'll
 * use the words "increase" & "decrease". If we wanna increase an interval by d, we
 * can greedily increase a suffix (instead of just an interval in the middle). If we
 * are to decrease an interval by d, we can greedily decrease a prefix. The two cases
 * are symmetric, so we can assume that one always increase a suffix by 0 <= d <= x.
 * And, if we're increasing a suffix, why don't we just do d=x? The rest is quite
 * straight-forward.
 * 
 * ------ C ------
 * For k_j = 0, we have to find the num of times each interval appeared. This can be
 * effectively done with str hashing. [S3] solved. [S1] is just brute-force: we can
 * do a O(n^2) for loop, iterating over all pairs of starting pos, naively comparing
 * the dist. of 2 substr. [S2] is a O(n^2) comparison between pairs of VALUES and
 * apply a difference array.
 * We're only looking for the num of mismatches. Let's compress the values (a_i:
 * 10^9 -> 10^4).
 * 
 * Time Complexity 1: O()
 * Time Complexity 2: O(n * log(n))
 * Time Complexity 3: O(n^2 + q) ([S1-2]), O(n)    (non-deterministic hashing)
 * Implementation 1         (Just for partials, [S1-2], [S3]. [S3] not finished)
*/
 
#include <bits/stdc++.h>
 
typedef int64_t     int_t;
typedef std::vector<int>    vec;
 
const int INF = 0x3f3f3f3f;
 
int_t pow(int_t a, int_t b, int_t mod) {
    int_t res = 1;
    while (b > 0) {
        if (b % 2 == 1)
            res = res * a % mod;
        a = a * a % mod, b /= 2;
    }
    return res;
}
 
struct RH {     // rolling hash
    std::vector<std::vector<int_t>> _p;
    std::vector<std::vector<int_t>> hash;
    RH(std::vector<std::vector<int_t>> params, const vec& values) {
        int sets = params.size(), n = values.size();
        hash.assign(sets, std::vector<int_t>(n + 1));
        _p = params;
        for (int i = 0; i < sets; i++) {
            int_t p = params[i][0], m = params[i][1];
            hash[i][0] = 0;
            for (int k = 0; k < n; k++) {
                hash[i][k + 1] = hash[i][k] * m % p + int_t(values[k]) % p;
                hash[i][k + 1] = (hash[i][k + 1] % p + p) % p;
            }
        }
    }
    inline std::vector<int_t> find_hash(int s, int l) {
        std::vector<int_t> ans;
        for (int i = 0; i < int(_p.size()); i++) {
            int_t p = _p[i][0], m = _p[i][1];
            int_t val = hash[i][s + l] - hash[i][s] * pow(m, l, p) % p;
            val = (val % p + p) % p;
            ans.push_back(val);
        }
        return ans;
    }
};
 
 
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
 
    int n, l;
    std::cin >> n >> l;
    vec values(n);
    for (int k = 0; k < n; k++)
        std::cin >> values[k];
        
 
    if (n <= 2000) {
        // Mismatch at i, j add 1 to the dist of (s, s+d)   (d = j-i)
        // 1 <= i-s+1 <= l, so max(i-l+1,0) <= s <= i.
        // Note that (l+1) means invalid.
        std::vector<vec> dist(n, vec(n, l + 1));
        for (int d = 1; d < n; d++) {
            vec diff(n + 1, 0);
            for (int i = 0; i + d < n; i++) {
                int j = i + d;
                if (values[i] != values[j])
                    diff[std::max(i - l + 1, 0)]++, diff[i + 1]--;
            }
            for (int i = 0, prefix = 0; i + d + l <= n; i++) {
                prefix += diff[i];
                dist[i][i + d] = prefix;
            }
        }
        for (int i = 0; i < n; i++) {
            dist[i][i] = l + 1;
            for (int j = i + 1; j < n; j++)
                dist[j][i] = dist[i][j];
        }
        std::vector<vec> pre(n, vec(l + 2, 0));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++)
                pre[i][dist[i][j]]++;
            for (int j = 1; j <= l + 1; j++)
                pre[i][j] += pre[i][j - 1];
        }
        int q;
        std::cin >> q;
        for (int _ = 0; _ < q; _++) {
            int sim;
            std::cin >> sim;
            for (int i = 0; i + l - 1 < n; i++)
                std::cout << pre[i][sim] << ' ';
            std::cout << '\n';
        }
    } else {    // [S3] assumes q=1 and k1=0
        // 3 is a primitive root of 998244353. Idk about 5
        RH hash({{998244353, 3}, {int_t(1e9) + 7, 5}}, values);
        std::map<std::vector<int_t>, int> count;
        for (int i = 0; i + l - 1 < n; i++) {
            std::vector<int_t> h = hash.find_hash(i, l);
            for (int_t a : h)
                std::cerr << a << ' ';
            std::cerr << std::endl;
        }
        for (int i = 0; i + l - 1 < n; i++)
            count[hash.find_hash(i, l)]++;
        for (int i = 0; i + l - 1 < n; i++)
            std::cout << count[hash.find_hash(i, l)] - 1 << ' ';
        std::cout << '\n';
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...