VP Codeforces Round 990 (Div. 2)

A. Alyona and a Square Jigsaw Puzzle

题意:一个人搭一个矩阵,一圈圈的围,每天放ai个方块,当某天正好搭出来一个矩阵他就开心。问有多少天是开心的。

发现每搭一圈,矩阵长度加2,不同边长矩阵需要的方块也可以算出来,按题意模拟就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    int tot = 1, len = 1;
    int ans = 0, sum = 0;
    for (int i = 0; i < n; ++ i) {
    	sum += a[i];
    	while (tot + len * 4 - 4 < sum) {
    		tot += len * 4 - 4;
    		len = len + 2;
    	}

    	if (tot + len * 4 - 4 == sum) {
    		++ ans;
    	}
    }

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

B. Replace Character

给你一个字符串,你必须进行一次操作把一个字符串里的字符变成字符串里的另一个字符,最后让全排列中不同的字符串最少。

我们应该让最多的字符尽可能多,因为每个相同的字符换位置还是相同的字符串。考虑应该把哪个字符换成最多的这个字符,我们应该换出现次数最少的那个(猜的)。

点击查看代码
void solve() {
    int n;
    std::string s;
    std::cin >> n >> s;
    std::vector<int> cnt(26);
    for (auto & c : s) {
    	++ cnt[c - 'a'];
    }

    int pmin = s[0] - 'a', pmax = s[0] - 'a';

    for (auto & c : s) {
    	if (cnt[c - 'a'] > cnt[pmax]) {
    		pmax = c - 'a';
    	}

    	if (cnt[c - 'a'] < cnt[pmin]) {
    		pmin = c - 'a';
    	}
    }

    if (pmin == pmax) {
    	if (cnt[pmax] != n) {
    		for (auto & c : s) {
    			if (c - 'a' != pmax) {
    				c = 'a' + pmax;
    				break;
    			}
    		}
    	}
    } else {
    	for (auto & c : s) {
    		if (c - 'a' == pmin) {
    			c = 'a' + pmax;
    			break;
    		}
    	}
    }

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

C. Swap Columns and Find a Path

题意:一个2*n的矩阵,你可以随意更改列的位置,只能向下或者向右,求从(1, 1)到(2, n)的最长路。

根据题意我们发现,我们有一个转折点,也就是向下的那一步,这一步前面都是走上面,后面都是走下面,但向下的这一列上下都走了。

于是我们枚举向下的这一列,其他列就取上下最大值就行。因为其他列上下要走且只能走一个。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    using PII = std::pair<i64, i64>;
    std::vector<PII> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i].first;
    }

    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i].second;
    }

    i64 ans = -1e18;
    for (int i = 0; i < n; ++ i) {
    	i64 sum = 0;
    	for (int j = 0; j < n; ++ j) {
    		if (j == i) {
    			continue;
    		}

    		sum += std::max(a[j].first, a[j].second);
    	}

    	ans = std::max(ans, sum + a[i].first + a[i].second);
    }

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

D. Move Back at a Cost

这题做我一个小时,最后发现这么简单,唐完了。

题意:给你一个数组,你可以操作任意次,每次把一个数加一后放到最后面,要让这个数组字典序最小。

开始模拟一下发现,应该每次把最小值的前面的非最小值都拿到后面去,wa2后发现后面一些值也要动,但还是wa2,然后发现自己首先不能保证复杂度正确,代码也不好写(因为我太菜了)。
最后十分钟发现每个数最多加一次,因为如果这个数后面有比他小的,他就一定要放后面,那么我们把所有要放后面的排个序就行了。除此之外,还有可能前面的比它小的数会放到后面,那么这个数也要放到后面。循环两次找要加1的数就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    std::vector<int> st(n);
    int min = 1e9;
    for (int i = n - 1; i >= 0; -- i) {
    	if (a[i] > min) {
    		st[i] = 1;
    	}

    	min = std::min(min, a[i]);
    }

    min = 1e9;
    for (int i = 0; i < n; ++ i) {
    	if (a[i] > min + 1) {
    		st[i] = 1;
    	}

    	if (st[i]) {
    		min = std::min(min, a[i]);
    	}
    }

    for (int i = 0; i < n; ++ i) {
    	a[i] += st[i];
    }

    std::sort(a.begin(), a.end());
    for (int i = 0; i < n; ++ i) {
    	std::cout << a[i] << " \n"[i == n - 1];
    }
}

E. Adventurers

赛后补题。

题意:有n个点,你要选一个(x0y0),让他的坐标系把所有点分成四份,要求每份最小的最大。

还是挺典的感觉。

首先一定有一个最优的点使得他的x坐标和y坐标都是已有点里出现过的。 证明:我们随便找一个最优的点,它可以移动他的点到挨着已有的点,这样不会改变每一份的大小,结果依然最优。

我们先离散化,维护一个y坐标的一维前缀和。那么我们按x坐标排序后枚举,维护x左边的纵坐标以及x右边的纵坐标,一开始将所有点纵坐标加到左边,然后按x从大到小枚举,这样方便一些,因为他的分界线上的点属于右边。
每次把新的点全部加入,更新左边和右边,接下来我们要对这个x坐标找到一个最优的y坐标,可以二分查找。首先给我们x和y可以求出四个部分的值,如果最小值在一二象限,那么我们为了更优,应该让最小值比变大,也就是往下走,否则往上走。
二分过程中记录一下答案就行,我用的树状数组维护区间和。

点击查看代码
struct Fenwick {
	int n;
	std::vector<int> tr;

	Fenwick(int _n) : n(_n) {
		tr.assign(_n + 1, 0);
	}

	void modify(int x, int v) {
		for (int i = x; i <= n; i += i & -i) {
			tr[i] += v;
		}
	}

	int query(int x) {
		if (x <= 0) {
			return 0;
		}

		int res = 0;
		for (int i = x; i ; i -= i & -i) {
			res += tr[i];
		}

		return res;
	}

	int sum(int l, int r) {
		return query(r) - query(l - 1);
	}
};

void solve() {
    int n;
    std::cin >> n;
    std::vector<std::pair<int, int> > a(n);
    std::vector<int> b;
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i].first >> a[i].second;
    	b.push_back(a[i].first);
    	b.push_back(a[i].second);
    }

    auto get = [&](int x) -> int {
    	return std::lower_bound(b.begin(), b.end(), x) - b.begin() + 1;
    };

    std::sort(b.begin(), b.end());
    b.erase(std::unique(b.begin(), b.end()), b.end());

    std::sort(a.begin(), a.end());
    for (auto & [x, y] : a) {
    	x = get(x);
    	y = get(y);
    }

    int m = b.size();

    Fenwick trl(m), trr(m);
    for (int i = 0; i < n; ++ i) {
    	trl.modify(a[i].second, 1);
    }

    auto check = [&](int x) -> std::array<int, 5> {
    	std::array<int, 5> res;
    	res[1] = trr.sum(x, m); res[2] = trl.sum(x, m);
    	res[3] = trl.sum(1, x - 1); res[4] = trr.sum(1, x - 1);
    	res[0] = std::min({res[1], res[2], res[3], res[4]});
    	return res;
    };

    int ans = 0, X = 0, Y = 0;
    for (int i = n - 1; i >= 0; -- i) {
    	int j = i;
    	while (j >= 0 && a[j].first == a[i].first) {
    		trr.modify(a[j].second, 1);
    		trl.modify(a[j].second, -1);
    		-- j;
    	}

    	int l = 1, r = m;
    	while (l <= r) {
    		int mid = l + r >> 1;
    		auto A = check(mid);
    		if (A[0] > ans) {
    			ans = A[0];
    			X = b[a[i].first - 1];
    			Y = b[mid - 1];
    		}
    		if (A[0] == A[1] || A[0] == A[2]) {
    			r = mid - 1;
    		} else {		
    			l = mid + 1;
    		}
    	}

    	i = j + 1;
    }

    std::cout << ans << "\n";
    std::cout << X << " " << Y << "\n";
}
posted @   maburb  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示