比赛链接:

https://ac.nowcoder.com/acm/contest/11187

C.哦~唔西迪西小姐

题目大意

\(n\) 个格子,格子有两类:冰格子和火格子。刚开始可以从任意一个格子开始走,也可以不走(即最后的得分为 0),到一个格子上就会获得它上面的得分 \(a\),只能从编号小的格子移动到与它类型一致的编号大的格子,现在可以在移动前更改不超过 \(m\) 个格子的属性。让它从冰变成火,或者从火变成冰,但是更改后会失去 \(p[i]\) 个得分。问最多可以得到多少得分。

思路:

首先注意,得分和改变类型后的损失分是有负数的,也就是说,有些格子更改类型后有可能会加分。
分两类考虑,走火格子和走冰格子。接下来以走火格子为例。
先将格子得分大于等于 0 的格子全部选上,然后接下来考虑换类型的情况。
若当前的格子为火格子,当格子得分大于等于 0 的时候,刚开始是走了,但是更改类型之后,走不了了,总得分要 \(- a[i] - p[i]\),格子得分小于 0 的时候,刚开始没走过,更改类型后,总得分 - \(p[i]\)
若当前格子为冰格子,当格子得分大于等于 0 的时候,更改类型之后要走,所以总得分 \(+ a[i] - p[i]\),当格子得分小于 0 的时候,改类型后也不走,总得分 \(- p[i]\)
最后取走火格子和走冰格子两个方案的最大值,再与 0 取最大值,因为可能一个格子都不走。

代码:

#include <bits/stdc++.h>
using namespace std;
#define IOS() ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define LL long long
#define pb push_back
#define all(x) (x).begin(), (x).end()
LL n, m;
int main(){
	IOS();
	cin >> n >> m;
	vector <LL> a(n), p(n), b(n);
	for (int i = 0; i < n; ++ i)
		cin >> a[i];
	for (int i = 0; i < n; ++ i)
		cin >> p[i];
	LL cfire = 0, cice = 0;
	for (int i = 0; i < n; ++ i){
		cin >> b[i];
		if (a[i] >= 0){
			if (b[i])
				cfire += a[i];
			else
				cice += a[i];
		}
	}
	vector <LL> ice, fire;
	for (int i = 0; i < n; ++ i)
		if (b[i]){
			if (a[i] >= 0)
				ice.pb(a[i] - p[i]);
			else
				ice.pb(- p[i]);
		}
		else{
			if (a[i] >= 0)
				ice.pb(- a[i] - p[i]);
			else
				ice.pb(- p[i]);
		}
	for (int i = 0; i < n; ++ i)
		if (b[i]){
			if (a[i] >= 0)
				fire.pb(- a[i] - p[i]);
			else
				fire.pb(- p[i]);
		}	
		else{
			if (a[i] >= 0)
				fire.pb(a[i] - p[i]);
			else
				fire.pb(- p[i]);
		}
	sort(all(ice), [](LL a, LL b){
		return a > b;
	});
	sort(all(fire), [](LL a, LL b){
		return a > b;
	});
	LL cnt = 0;
	for (auto x : ice)
		if (x > 0){
			cice += x;
			cnt++;
			if (cnt >= m) break;
		}
	cnt = 0;
	for (auto x : fire)
		if (x > 0){
			cfire += x;
			cnt++;
			if (cnt >= m) break;
		}
	cout << max( max(cfire, cice), 0LL ) << "\n";
	return 0;
}

D.月之暗面

题目大意:

\(n\) 个点的树,有 \(x\) 个普通颜色,\(y\) 个特殊颜色,给树上每一个节点染色,普通颜色没有限制,但相邻的两个节点不能染相同颜色的特殊颜色,求染色方案数,结果对 998244353 取模。

思路:

树形 dp。每一个节点两个属性,该节点染普通颜色时的方案数,染特殊颜色的时的方案数。
染普通颜色的话,没有限制,所以可以从所有相邻节点的各种方案 * 普通颜色的数量转移过来。
染特殊颜色的话,不能与相邻节点染同样的特殊颜色,所以只能从相邻节点的普通颜色的方案 * 特殊颜色的数量转移,以及从相邻节点的特殊颜色的方案 * (特殊颜色的数量 - 1)转移。

代码:

#include <bits/stdc++.h>
using namespace std;
#define IOS() ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define LL long long
#define pb push_back
const int mod = 998244353, N = 1e6 + 10;
LL T = 1, n, p, q, dp[N][2], v[N];
vector <LL> e[N];
void dfs(LL x){
	v[x] = 1;
	dp[x][0] = 1;
	dp[x][1] = 1;
	for (auto y : e[x]){
		if (v[y]) continue;
		dfs(y);
		dp[x][0] = ( ( dp[y][0] * p + dp[y][1] * q ) % mod * dp[x][0] ) % mod;
		dp[x][1] = ( ( dp[y][0] * p + dp[y][1] * (q - 1) ) % mod * dp[x][1] ) % mod;
	}
}
void solve(){
	cin >> n >> p >> q;
	for (int i = 1; i < n; ++ i){
		LL a, b;
		cin >> a >> b;
		e[a].pb(b);
		e[b].pb(a);
	}
	dfs(1);
	cout << ( ( dp[1][0] * p ) % mod + ( dp[1][1] * q % mod) ) % mod << "\n";
}
int main(){
	IOS();
	while(T--)
		solve();
	return 0;
}
posted on 2022-03-11 09:42  Hamine  阅读(52)  评论(0编辑  收藏  举报