AtCoder Beginner Contest 372(部分

UNIQUE VISION Programming Contest 2024 Autumn (AtCoder Beginner Contest 372) - AtCodericon-default.png?t=O83Ahttps://atcoder.jp/contests/abc372

D - Buildings

题意:N座建筑编号1-N,问第i座建筑右边有多少座建筑j使i-j之间没有建筑高于j。

思路:利用单调栈,从右向左维护一个单调递减的栈,遍历到的i的ans就是当时栈的size。

直接上code吧

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
const int maxn = 2e5 + 10;
void solve()
{
	int n;
	cin >> n;
	std::vector<int> a(n);
	for(int i = 0; i < n; i++)
		cin >> a[i];
	std::vector<int> ans(n);
	std::vector<int> stk;
	for(int i = n - 1; i >= 0; i--)
	{		
		ans[i] = stk.size();
		while(stk.size() && stk.back() < a[i]) {
			stk.pop_back();
		}
		stk.push_back(a[i]);
	}
	for(int i = 0; i < n; i++)
		cout << ans[i] << " \n"[i == n - 1];
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	solve();
	return 0;
}

E - K-th Largest Connected Components

题意:给你n个散点。定义两种操作, 操作1:1 u v 连接u v, 操作2: 2 v k 问点v所在的联通块编号第k大的顶点。(k <= 10);

思路:利用并查集暴力维护每个联通块前10大的顶点就行

code:

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
const int maxn = 2e5 + 10;
std::vector<int> e[maxn];
int anc[maxn];
int find(int x)
{
	return anc[x] == x ? x : anc[x] = find(anc[x]);
}
void solve()
{
	int n, q;
	cin >> n >> q;
	int op, v, u;
	for(int i = 1; i <= n; i++)
		anc[i] = i, e[i] = {i};
	for(int i = 1; i <= q; i++)
	{
		cin >> op >> u >> v;
		if(op == 1) 
		{
			u = find(u);
			v = find(v);
			if(u == v) continue;
			e[u].insert(e[u].end(), e[v].begin(), e[v].end());
			sort(e[u].rbegin(), e[u].rend());
			if(e[u].size() > 10) e[u].resize(10);
			anc[v] = u;
		}
		if(op == 2)
		{
			auto & s = e[find(u)];
			if(v <= (int) s.size())
			{
				cout << s[v - 1] << '\n';
			}
			else cout << "-1\n";
		}
	}

}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	solve();
	return 0;
}

F - Teleporting Takahashi 2

题意:给一个有向环 1 -> 2 -> 3 -> 4 -> .....  -> n - >  连m条有向边(m<= 50)问从1开始经过k个顶点有多少种方案数

思路:发现m很小,考虑从此处入手,发现如果一个点i不是特殊点(没被那m条边中的一条连接的)时只能  往i + 1走,即只有特殊点会对总的方案数产生贡献,因此我们只需要考虑特殊点的状态转移就行了。当此时在特殊点时,我们只考虑往下一个最近的特殊点和另一个与该特殊点相连的特殊点进行转移。但特殊点的编号值可以取满n(小于2e5),k <= 2e5 如果暴力开dp[n][k]必然爆空间,且产生了很大的浪费,怎么解决??? 发现经典的值域大数量小,考虑离散化。方法是开一个id数组,把m个特殊点离散化,记录编号就行,这是空间被优化成m*k的,1e7级别的.. 可以接受! 具体的细节看code

#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
const int maxn = 2e5 + 10;
const int mod = 998244353;
std::vector<int> e[maxn];
int dp[110][maxn];
std::vector<int> nodes = {1};
int id[maxn];
int nxt[maxn];
void solve()
{
	int n, m, k;
	cin >> n >> m >> k;
	int x, y;
	for(int i = 1; i <= m; i++)
	{
		cin >> x >> y;
		e[x].push_back(y);
		nodes.push_back(x);
		nodes.push_back(y);
	}
	sort(nodes.begin(), nodes.end());
	nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());
	int S = nodes.size();
	nxt[nodes[S - 1]] = 1;
	for(int i = 0; i < S - 1; i++){
		nxt[nodes[i]] = nodes[i + 1];
	}
	for(int i = 0; i < S; i++) {
		id[nodes[i]] = i;
	}
	int ans = 0;
	dp[0][0] = 1;
	for(int i = 0; i < k; i++)
	{
		for(int j = 0; j < S; j++)
		{
			int x = nodes[j];
			for(auto k : e[x]) {
				dp[id[k]][i + 1] = (dp[j][i] + dp[id[k]][i + 1]) % mod;
			}
			int weight = nxt[x] - x;
			if(weight <= 0) weight += n;
			if(i + weight > k) ans = (ans + dp[j][i]) % mod;
			else dp[id[nxt[x]]][i + weight] = (dp[id[nxt[x]]][i + weight] + dp[j][i]) % mod;
		}
	}
	for(int i = 0; i < S; i++)
		ans = (ans + dp[i][k]) % mod;
	cout << ans << '\n';	
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	solve();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值