列表

详情


NC241488. 吟游诗人

描述

Background


「若你困于无风之地,

我将奏响高天之歌。」

如风般自由的吟游诗人,驻于牧歌之城。

--------------------------------------------------------------------

「我现在会为你歌颂美好的万物万象——

四季轮转,四风从不止息。

当然啦,功劳也不是它们的,主要是我的。

要是没有吟游诗人,谁去把这些传唱?」

                           ——当温迪彻底沉醉于美酒时,他会如此放声歌唱。

Description


为了争夺蒙德第一吟游诗人的名号,六指乔瑟决定向温迪发起挑战。

具体来说,一张未完成的乐谱被定义为一个长度为 n 的音符序列 。而完成这张乐谱需要将它划分成恰好 k 个乐章,每个乐章的响度被定义为其中所有音符的权值之和。众所周知,蒙德的风是宁静祥和的,所以温迪认为一张完成的乐谱的动听度可以被其中响度最大的乐章刻画,且该最大响度越小则乐谱演奏出来越好听。

六指乔瑟自然不能任由温迪演奏出好听的乐曲,于是他们约定,六指乔瑟可以在温迪完成初始乐谱 c 之前对其做一些变换,以得到需要温迪完成的乐谱 d。具体来说,存在一个长度为 n 的置换 f,六指乔瑟可以对 c 做不超过 T 次置换得到 d,即

温迪和六指乔瑟都是绝顶聪明的吟游诗人,在比赛完成之前你想知道最终演奏出来的乐谱的动听度是多少。

输入描述

第一行三个正整数 n, k, T

第二行 n 个整数描述初始序列 c

第三行 n 个正整数描述置换 f

输出描述

一个整数表示答案。

示例1

输入:

8 1 6
0 -7 8 -1 -3 9 -8 5
4 7 2 8 3 6 5 1

输出:

3

示例2

输入:

9 6 9
-1 -7 -10 -1 -5 5 8 -10 9
7 4 1 2 8 6 5 3 9

输出:

7

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 1016ms, 内存消耗: 15096K, 提交时间: 2022-09-09 19:56:31

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

void chk(int &x, int y) {
    if (x > y) x = y;
}

struct BIT {
    vector<int> c;
    BIT(int n) : c(n + 1, 1e9) {}

    void ins(int p, int v) {
        for (p++; p; p -= p & -p) chk(c[p], v);
    }
    int query(int p) {
        int s = 1e9;
        for (p++; p < c.size(); p += p & -p) chk(s, c[p]);
        return s;
    }
};

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    int n, k, T;
    cin >> n >> k >> T;
    vector<int> c(n);
    for (int &x : c) {
        cin >> x;
    }
    vector<int> p(n), q(n);
    iota(p.begin(), p.end(), 0);
    for (int &x : q) {
        cin >> x, x--;
    }
    vector a(T + 1, vector<int>(n));
    for (int t = 0; t <= T; t++) {
        for (int i = 0; i < n; i++) {
            a[t][i] = c[p[i]];
        }
        vector<int> _p(n);
        for (int i = 0; i < n; i++) {
            _p[i] = q[p[i]];
        }
        swap(p, _p);
    }
    ll ans = -1e13;
    vector<int> perm(T + 1);
    iota(perm.begin(), perm.end(), 0);
    shuffle(perm.begin(), perm.end(), mt19937(time(0)));
    for (int t : perm) {
        vector<ll> s(n + 1);
        for (int i = 0; i < n; i++) {
            s[i + 1] = s[i] + a[t][i];
        }
        auto val = s;
        sort(val.begin(), val.end());
        val.resize(unique(val.begin(), val.end()) - val.begin());
        vector<int> pos(n + 1);
        for (int i = 0; i <= n; i++) {
            pos[i] = lower_bound(val.begin(), val.end(), s[i]) - val.begin();
        }
        auto chk = [&](ll lim) {
            vector<int> f(n + 1), g(n + 1);
            BIT c1(val.size()), c2(val.size());
            c1.ins(pos[0], f[0] = 0), c2.ins(pos[0], g[0] = 0);
            for (int i = 1; i <= n; i++) {
                int j = lower_bound(val.begin(), val.end(), s[i] - lim) - val.begin();
                c1.ins(pos[i], f[i] = c1.query(j) + 1);
                c2.ins(pos[i], g[i] = c2.query(j) - 1);
            }
            return f[n] <= k && -g[n] >= k;
        };
        ll l = ans, r = 1e13;
        if (chk(l)) continue;
        while (l <= r) {
            ll mid = (l + r) / 2;
            chk(mid) ? r = (ans = mid) - 1 : l = mid + 1;
        }
    }
    cout << ans << "\n";
    return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 662ms, 内存消耗: 16092K, 提交时间: 2022-09-11 19:41:48

#include <bits/stdc++.h>
const int MaxN = 2e3 + 5;
const int inf = 1e9;
using ll = long long;
std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());

int n, k, T, f[MaxN], b[MaxN][MaxN]; ll s[MaxN];
int c1[MaxN], c2[MaxN], dp1[MaxN], dp2[MaxN];

bool check(int a[], ll t)
{
	for(int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i];
	std::vector<ll> V(s + 1, s + n + 1);
	std::sort(V.begin(), V.end());
	auto rk = [&](ll x) { return std::lower_bound(V.begin(), V.end(), x) - V.begin() + 1; };
	
	std::fill(c1 + 1, c1 + n + 1, inf);
	std::fill(c2 + 1, c2 + n + 1, -inf);
	std::fill(dp1 + 1, dp1 + n + 1, inf);
	std::fill(dp2 + 1, dp2 + n + 1, -inf);
	
	for(int i = 1; i <= n; ++i)
	{
		if(s[i] <= t) dp1[i] = dp2[i] = 1;
		for(int x = n - rk(s[i] - t) + 1; x; x -= (x & -x))
		{
			dp1[i] = std::min(dp1[i], c1[x] + 1);
			dp2[i] = std::max(dp2[i], c2[x] + 1);
		}
		
		for(int x = n - rk(s[i]) + 1; x <= n; x += (x & -x))
		{
			c1[x] = std::min(c1[x], dp1[i]);
			c2[x] = std::max(c2[x], dp2[i]);
		}
	}
	
	return (dp1[n] <= k && k <= dp2[n]);
}

int main()
{
	std::cin >> n >> k >> T;
	for(int i = 1; i <= n; ++i) std::cin >> b[0][i];
	for(int i = 1; i <= n; ++i) std::cin >> f[i];
	
	for(int i = 1; i <= T; ++i)
	for(int j = 1; j <= n; ++j) b[i][j] = b[i - 1][f[j]];
	
	std::vector<int> p(T + 1);
	std::iota(p.begin(), p.end(), 0);
	std::shuffle(p.begin(), p.end(), rng);
	
	ll ans = -2e12;
	for(int i : p) if(!check(b[i], ans))
	{
		ll l = ans, r = 2e12;
		while(l <= r)
		{
			ll mid = l + (r - l) / 2;
			if(check(b[i], mid)) ans = mid, r = mid - 1;
			else l = mid + 1;
		}
	}
	
	std::cout << ans << "\n";
	return 0;
}

上一题