[CCPC 2024 哈尔滨站] CCPC 2024 分站赛哈尔滨站重现赛 题解

比赛链接

P14803 [CCPC 2024 哈尔滨站] 在哈尔滨指路

直接模拟即可

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

map<char,int> f;

void solve()
{
	int n,x = 0,y = 0;
	char op,c; int d;
	cin >> n; n--;
	cin >> op >> d;
	cout << (n + 1) * 2 - 1 << " " << op << "\n";
	cout << "Z " << d << "\n";
	while(n--)
	{
		cin >> c >> d;
		if(f[c] == 4 && f[op] == 1) cout << "L\n";
		else if(f[c] == 1 && f[op] == 4) cout << "R\n";
		else cout << (f[c] > f[op]? "R\n" : "L\n");
		cout << "Z " << d << "\n";
		op = c;
	}
	// cout.flush();
}

int main()
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	
	f['N'] = 1; f['E'] = 2; f['S'] = 3; f['W'] = 4;
	int T; cin >> T;
	while(T--) solve();
	return 0;
}

2发罚时,死因:没看到“保证相邻两个指令中 d 不相同且不相反(北与南互相相反,西与东互相相反)。” ……

P14807 [CCPC 2024 哈尔滨站] 欢迎加入线上会议!

bfs 即可

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

const int N = 2e5 + 5,M = 5e5 + 5;

int n,m,k,a[N];
vector<int> G[N];

int main()
{
	cin >> n >> m >> k;
	for(int i = 1,x; i <= k; i++) cin >> x,a[x] = 1;
	
	int u,v;
	while(m--) cin >> u >> v,G[u].push_back(v),G[v].push_back(u);
	
	if(n == k) { cout << "No\n"; return 0; }
	int root = 0;
	for(int i = 1; i <= n; i++) if(!a[i]) { root = i; break; }
	
	vector<vector<int> > g;
	queue<int> q; q.push(root); vector<bool> vis(n + 1); vis[root] = 1;
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		if(a[x]) continue;
//		cout << x << "\n";
		vector<int> tp; tp.push_back(x);
		for(int i : G[x]) if(!vis[i]) tp.push_back(i),q.push(i),vis[i] = 1;
		if(tp.size() > 1) g.push_back(tp);
	}
	
//	cout << "bfs done.";
	
	for(int i = 1; i <= n; i++) if(vis[i] == 0) { cout << "No\n"; return 0; }
	cout << "Yes\n" << g.size() << "\n";
	for(vector<int> p : g)
	{
		cout << p[0] << " " << p.size() - 1 << " ";
		for(int i : p) if(i != p[0]) cout << i << " ";
		cout << "\n";
	}
	return 0;
}

罚时一发,死因:没判他一个人也没法扩展。

P14811 [CCPC 2024 哈尔滨站] 农场经营

首先注意到有一下贪心:

  • \(m\)\(w\) 最大的
  • \(m\)\(w\) 最小的

第一个容易实现,不赘述:

ll s = 0,c = 0;
for(int i = 1; i <= n; i++)
	s += a[i].l * a[i].w,c += a[i].l;

ll ans1 = s + a[n].w * (m - c);

第二个在实现中发现问题,把 \(m\) 给最小的意义是把空出来的 \(L_{min}\)\(w_{max}\) 的。
但是 \(w_{max}\) 最多只能拿 \(R_{max}\) 个,剩余的应该分给 \(w_{sec}\)……以此类推。
我们发现可能存在一个 \(i\)\(w_i\) 可能不是最小的,但是 \(L_i\) 很大,即换成 \(w_{max}\) 时能换很多,于是还得枚举。

我们枚举换哪一个作物,发现这样是 \(O(n^2)\) 的,考虑优化。
注意到我们按照 \(L\) 升序排序后,能替换的 \(w\) 大的作物数量只会变多,维护一个 \(p\) 表示现在 \((p,n]\) 可以满(达到 \(R\)),\(p\) 能多余 \(L\),但达不到 \(R\),复杂度降到了 \(O(n \log n)\)

然后可以愉快的通过了。
通过后笔者认为这是一道绿题,因为至少比P14810 [CCPC 2024 哈尔滨站] 新能源汽车难,但是一看题解就被二分解法无语了,关键是我的代码复杂度高时间复杂度还一样……

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

typedef long long ll;
const int N = 2e5 + 5;

ll n,m;
struct Type { ll w,l,r; } a[N];
bool cmp(Type x,Type y) { return x.w < y.w; }
bool cmp2(Type x,Type y) { return x.l < y.l; }

int main()
{
	cin >> n >> m;
	for(int i = 1; i <= n; i++) cin >> a[i].w >> a[i].l >> a[i].r;
	sort(a + 1,a + n + 1,cmp);
	
	ll s = 0,c = 0;
	for(int i = 1; i <= n; i++)
		s += a[i].l * a[i].w,c += a[i].l;
	
	ll ans1 = s + a[n].w * (m - c);
	
	ll ans2 = 0,sum = s;
	sort(a + 1,a + n + 1,cmp2);
	vector<array<ll,2> > g;
	for(int i = 1; i <= n; i++) g.push_back({a[i].w,a[i].r - a[i].l});
	sort(g.begin(),g.end());
	
	int p = g.size() - 1;
	for(int i = 1; i <= n; i++)
	{
		ll rest = a[i].l - a[i - 1].l;
		if(i == 1) rest += m - c;
		while(rest && p >= 0)
		{
			if(g[p][1] > rest) g[p][1] -= rest,sum += g[p][0] * rest,rest = 0;
			else sum += g[p][0] * g[p][1],rest -= g[p][1],p--;
		}
		sum += a[i - 1].w * a[i - 1].l;
		sum -= a[i].w * a[i].l;
		ans2 = max(ans2,sum);
	}
	
	ll ans = max(ans1,ans2);
	cout << ans << "\n";
	return 0;
}

P14810 [CCPC 2024 哈尔滨站] 新能源汽车

有显然贪心策略:尽量取即将加满的
具体化:按照距离排序,从近到远取
特判“都取完了”:把永远不会充电的电瓶初始电量和记为一个 res,减 res 即可
具体化:用优先队列实现,记录每个位置的 nxt,每次充电时把 nxt 放入队列。

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

typedef long long ll;
const int N = 1e5 + 5;

ll n,m,a[N],v[N];
ll d[N],t[N],nxt[N];

void solve()
{
	cin >> n >> m;
	for(int i = 1; i <= n; i++) cin >> a[i],v[i] = a[i];
	for(int i = 1; i <= m; i++) cin >> d[i] >> t[i];
	
	vector<int> id(n + 1);
	for(int i = m; i >= 1; i--)
	{
		nxt[i] = id[t[i]];
		id[t[i]] = i;
	}
	priority_queue<array<ll,2>,vector<array<ll,2> >,greater<array<ll,2> > > q;
	ll res = 0;
	for(int i = 1; i <= n; i++) if(id[i]) q.push({d[id[i]],i}); else res += v[i],v[i] = 0;
	for(int i = 1; i <= m; i++)
	{
		ll dis = d[i] - d[i - 1];
		while(!q.empty() && dis)
		{
			int x = q.top()[1];
			if(dis >= v[x]) dis -= v[x],v[x] = 0,q.pop();
			else v[x] -= dis,dis = 0;
		}
		if(dis)
		{
			if(dis > res) { for(int i = 1; i <= n; i++) assert(v[i] == 0); cout << d[i] - (dis - res) << "\n"; return; }
			res -= dis,dis = 0;
		}
//		for(int j = 1; j <= n; j++) cout << v[j] << " "; cout << "\n";
		v[t[i]] = a[t[i]]; if(nxt[i]) q.push({d[nxt[i]],t[nxt[i]]}); else res += v[t[i]],v[t[i]] = 0;
		while(!q.empty() && q.top()[0] <= d[i]) q.pop();
//		cout << t[i] << ":\n";
//		for(int j = 1; j <= n; j++) cout << v[j] << " "; cout << "\n";
	}
	ll ans = res;
	for(int i = 1; i <= n; i++) ans += v[i];
	cout << ans + d[m] << "\n";
}

int main()
{
	int T; cin >> T;
	while(T--) solve();
	return 0;
}
posted @ 2025-12-22 22:21  cshur  阅读(0)  评论(0)    收藏  举报