Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <algorithm>
- #include <map>
- #include <vector>
- #include <random>
- #include <fstream>
- #include <cstdlib>
- using namespace std;
- const int NMAX = 5010;
- typedef long long i64;
- vector <int> last_ap[NMAX];
- vector<i64> dp[NMAX];
- struct SuffixArray {
- int n, csz;
- vector<vector<int>> classes;
- vector<int> cnt, order, oldc, newc, left;
- vector<int> str;
- SuffixArray(vector<int> s, bool cyclic) :
- n(s.size() + !cyclic), csz(n + 5), cnt(csz),
- order(n), oldc(n), newc(n), left(n), str(s) {
- if (!cyclic) str.push_back(0);
- }
- vector<int> Build() {
- for (int i = 0; i < n; ++i) {
- oldc[i] = newc[i] = str[i];
- order[i] = left[i] = i;
- }
- for (int step = 1; step <= 2 * n; step *= 2) {
- // Counting sort (can be replaced by sort with left)
- // although not trivial
- fill(cnt.begin(), cnt.end(), 0);
- for (int i = 0; i < n; ++i) ++cnt[oldc[left[i]]];
- for (int i = 1; i < csz; ++i) cnt[i] += cnt[i - 1];
- for (int i = n - 1; i >= 0; --i)
- order[--cnt[oldc[left[i]]]] = left[i];
- newc[order[0]] = 0;
- for (int i = 1; i < n; ++i) {
- int now1 = order[i], last1 = order[i - 1],
- now2 = (now1 + step / 2) % n,
- last2 = (last1 + step / 2) % n;
- newc[now1] = newc[last1] + (oldc[now1] != oldc[last1]
- or oldc[now2] != oldc[last2]);
- }
- classes.push_back(newc);
- swap(oldc, newc);
- for (int i = 0; i < n; ++i) {
- left[i] = (order[i] + n - step) % n;
- }
- }
- return order;
- }
- int Compare(int i, int j, int len) {
- for (int step = 0; len; ++step, len /= 2) {
- if (len % 2 == 0) continue;
- int ret = classes[step][i] - classes[step][j];
- if (ret != 0) return ret < 0 ? -1 : 1;
- i = (i + (1 << step)) % n;
- j = (j + (1 << step)) % n;
- }
- return 0;
- }
- int GetLCP(int i, int j) {
- if (i == j) return str.back() == 0 ? n - i - 1 : n;
- int ans = 0;
- for (int step = classes.size() - 1; step >= 0; --step) {
- if (classes[step][i] == classes[step][j]) {
- i = (i + (1 << step)) % n;
- j = (j + (1 << step)) % n;
- ans += (1 << step);
- }
- }
- return min(ans, n); // if cyclic
- }
- };
- int32_t CLASS[NMAX][NMAX];
- void test()
- {
- int n, Add, Copy, Paste;
- cin >> n >> Add >> Copy >> Paste;
- map<int, int> rndmap;
- auto norm = [&](int x) {
- if (rndmap.count(x)) return rndmap[x];
- return rndmap[x] = rndmap.size() + 1;
- };
- vector<int> v(n);
- for (int i = 0; i < n; ++i) {
- cin >> v[i];
- v[i] = norm(v[i]);
- }
- SuffixArray sa(v, false);
- auto order = sa.Build();
- order.erase(order.begin());
- int last = -1;
- for (int i = 0; i < n; ++i) {
- int now = order[i];
- if (last == -1) {
- for (int j = now; j <= n; ++j) {
- CLASS[now + 1][j + 1] = 1;
- }
- } else {
- int lcp = sa.GetLCP(last, now);
- for (int j = now; j <= n; ++j) {
- int l = j - now + 1;
- if (last + l > n) {
- CLASS[now + 1][j + 1] = i + 1;
- } else {
- CLASS[now + 1][j + 1] = CLASS[last + 1][last + l];
- if (l > lcp) CLASS[now + 1][j + 1] += 1;
- }
- }
- }
- last = now;
- }
- for (int i = 0; i <= n + 2; ++i) {
- last_ap[i].assign(n + 2, -1);
- }
- for (int i = 0; i < n + 2; ++i) {
- dp[i].assign(n + 2, 1e18);
- }
- dp[1][0] = 0;
- for (int i = 1; i <= n; i++) {
- for (int j = i; j <= n; j++) {
- /// vreau sa obtin o subsecventa
- auto valh = CLASS[i][j];
- int l = (j - i + 1);
- if (last_ap[j - i][valh] != -1) {
- /// pot sa vin de acolo
- int former_dr = last_ap[j - i][valh]; /// am dat copy paste ultima data
- /// si s-a copat pana la former_i
- int added = (i - former_dr - 1);
- dp[i][j] = min(dp[i][j], dp[former_dr - l + 1][former_dr] + Paste +
- 1LL * added * Add);
- dp[i][j] = min(dp[i][j], dp[i][i - 1] + Copy + Paste);
- }
- }
- for (int j = 1; j <= i; j++) {
- dp[i + 1][i] = min(dp[i + 1][i], Add + dp[j][i - 1]);
- dp[i + 1][i] = min(dp[i + 1][i], dp[j][i]);
- }
- for (int j = 1; j <= i; j++)
- dp[j][i] = min(dp[j][i], dp[i + 1][i] + Copy);
- for (int st = 1; st <= i; st++) {
- /// adaug in hash secventa (st, i)
- int l = (i - st + 1);
- auto valh = CLASS[st][i];
- last_ap[i - st][valh] = i;
- }
- }
- cout << dp[n + 1][n] << '\n';
- }
- int32_t main()
- {
- int t;
- cin >> t;
- for (int i = 1; i <= t; i++) {
- cout << "Case #" << i << ": ";
- test();
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement