4.25小测总结
T3
一道状压 \(dp\) 唐题,但赛时太困了没切出来。
不难发现可以设 \(f_{i,S}\) 为考虑前 \(i\) 个动物,\([i,i+5)\) 区间的动物选取状态为 \(S\) 的答案(低位代表 \(i\))。
先抛开这是一个环,考虑当这是一条链时,我们要怎么做。
可以预处理 \(num_{i,S}\) 为 \([i,i+5)\) 的选取状态为 \(S\) 时,所有站在 \(i\) 位置的开心细佬(hhh)的个数。
那么转移即为 $f_{i,S}=\max(f_{i-1,(S&15)<<1})+num_{i,(S\(15)<<1|1}\)。
那么再把环考虑进来,
不难想到可以枚举开始 \(5\) 个位置的状态,设其为 \(T\),那么最终の答案即为 \(f_{n,T}\)。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 7, C = 5e4 + 7;
int n, c;
int num[N][40], dp[N][40];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> c;
for(int i = 1; i <= c; i++){
int e, f, l;
cin >> e >> f >> l;
int love = 0, hate = 0;
for(int j = 1, x; j <= f; j++){
cin >> x;
love |= (1 << (x - e + n) % n);
}
for(int j = 1, x; j <= l; j++){
cin >> x;
hate |= (1 << (x - e + n) % n);
}
for(int j = 0; j < 32; j++){
if((j & love) || ((~j) & hate)) num[e][j]++;
}
}
int ans = 0;
for(int T = 0; T < 32; T++){
memset(dp[0], 128, sizeof(dp[0]));
dp[0][T] = 0;
for(int i = 1; i <= n; i++){
for(int S = 0; S < 32; S++){
dp[i][S] = max(dp[i - 1][((S & 15) << 1)], dp[i - 1][((S & 15) << 1) | 1]) + num[i][S];
}
}
ans = max(ans, dp[n][T]);
}
printf("%d\n", ans);
return 0;
}
T4
题解:
一道状压 dp 和树形 dp 结合的好题。
删边的操作显然是比较不好处理的,我们考虑将其转换为求最大残留边权,答案即为总边权减去最大添加边权。
对于所有非树边,如果添加其所得到的环是偶环,便可以将其直接删去,不考虑到后续的讨论范围中。
考虑两个共顶点的奇环,不难发现这两个环可以合成一个偶环,因此要求不能存在两个奇环共顶点。
这就要求最终的图为一个仅存在奇环的仙人掌图。
由于每个点的度数不超过 \(10\),状压儿子是否被考虑。
设 \(f_{i,S}\) 为以 \(i\) 为根的子树中不考虑儿子集合 \(S\) 的最大残留边权。
若不考虑非树边,则
对于每一条连接 \(u,v\) 的非树边:
设 \(t=\operatorname{lca}(u,v)\)。
此时 \(u \rightarrow t \rightarrow v \rightarrow u\) 形成了一个环。
由于不能存在两个环共顶点,因此在这个环上的点强制其不被考虑。
所以对于所有在环上的点,其父亲的贡献都为 \(f_{fa_u,u}\) 而非 \(f_{fa_u,0}\)。
设 \(u,v\) 分别在 \(t\) 的 \(x,y\) 子树上。
所以转移方程便为
Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 1007, M = 5007, U = 1 << 10;
int n, m;
int lg[N], st[N][17], idx[N], dfn[N], cnt;
int dep[N], son[N], id[N], fa[N];
int f[N][U + 7];
struct Node{
int x, y, w;
};
vector<Node>g[N];
struct Edge{
int head[N], tot = 1;
int dfn[N], idx[N], cnt;
bool vis[M << 1];
struct edge{
int to, w, pre;
}e[M << 1];
void add(int x, int y, int z){
e[++tot] = {y, z, head[x]};
head[x] = tot;
}
void build_ST(){
for(int j = 1; (1 << j) <= n; j++){
for(int i = 1; i + (1 << j) - 1 <= n; i++){
st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
}
}
}
int lca(int x, int y){
if(x == y) return x;
x = dfn[x];
y = dfn[y];
if(x > y) swap(x, y);
int d = lg[y - x];
return idx[min(st[x + 1][d], st[y - (1 << d) + 1][d])];
}
void dfs1(int u, int father){
dfn[u] = ++cnt;
idx[cnt] = u;
st[cnt][0] = dfn[father];
fa[u] = father;
for(int i = head[u]; i; i = e[i].pre){
int v = e[i].to;
if(v == fa[u] || e[i].w) continue;
dep[v] = dep[u] + 1;
id[v] = son[u]++;
dfs1(v, u);
}
}
void doit(){
for(int u = 1; u <= n; u++){
for(int i = head[u]; i; i = e[i].pre){
int v = e[i].to;
if(v == fa[u] || !e[i].w || vis[i]) continue;
vis[i] = vis[i ^ 1] = 1;
if((dep[u] + dep[v]) % 2 == 0){
g[lca(u, v)].push_back(Node{u, v, e[i].w});
}
}
}
}
void dp(int u){
for(int i = head[u]; i; i = e[i].pre){
int v = e[i].to;
if(v == fa[u] || e[i].w) continue;
dp(v);
for(int S = 0; S < U; S++){
if(!(S & (1 << id[v]))) f[u][S] += f[v][0];
}
}
for(Node tmp : g[u]){
int x = tmp.x, y = tmp.y, w = tmp.w;
if(x != u){
w += f[x][0];
while(fa[x] != u){
w += f[fa[x]][1 << id[x]];
x = fa[x];
}
}
else x = -1;
if(y != u){
w += f[y][0];
while(fa[y] != u){
w += f[fa[y]][1 << id[y]];
y = fa[y];
}
}
else y = -1;
int T = 0;
if(x != -1) T |= (1 << id[x]);
if(y != -1) T |= (1 << id[y]);
for(int S = 0; S < U; S++){
if((S & T) == 0) f[u][S] = max(f[u][S], f[u][S | T] + w);
}
}
}
}E;
void init(){
for(int i = 2; i <= N - 7; i++) lg[i] = lg[i >> 1] + 1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
init();
int sum = 0;
for(int i = 1; i <= m; i++){
int x, y, z;
cin >> x >> y >> z;
E.add(x, y, z);
E.add(y, x, z);
sum += z;
}
memset(st, 0x3f, sizeof(st));
E.dfs1(1, 0);
E.build_ST();
E.doit();
E.dp(1);
printf("%d\n", sum - f[1][0]);
return 0;
}
浙公网安备 33010602011771号