比赛链接:
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;
}