[BalticOI 2021] The Xana coup (Day2)
巳时,闲来无事,学分数规划至正午,忽觉无用,遂大悲,阅洛谷题库以寻题,钦四五题以切,遇此好题。
题意。
一棵 \(N\) 个点的树,点权不是 0 就是 1。
我们有一个神秘的操作,我们先选择一个点,把它和所有的相邻点权都取反。
询问最小的操作次数,使得所有的点权最后都为 0。
\(N\) 是 \(1e5\) 级别
做法
如果思考这个问题的特点,我们会发现这个东西跟顺序是没有关系的,因为我们如果确定了某个点的操作次数,什么时候进行显然都是一样的。
于是我们可以通过子树合并的顺序进行,每次对父亲产生的约束仅仅会向上一层,所以我们可以尝试使用树形dp.
怎么设计状态?不难想到设 dp[u][0/1] 代表 \(u\) 子树,不会/会 影响到父亲的,保证树中清空的最小操作次数。
然而这个样子我们似乎并没办法去进行转移,原因是我们不清楚何时进行操作,我们的转移一定是基于我们进行的操作的。
既然不知道,我们便可以把这个东西设进状态。
可以看出,一个点操作偶数次相当于没操作,所以我们加一维 0/1 表示这个点经历了若干次操作 没有/有 被改变。
对应的,dp 数组定义中需要加上所清空范围不包含 u 节点。
理论上应该是能做了,先试着列一下转移式子,有需要再进行添加。
\(v \in son[u]\),我们扫到一个子树,无非就是受不受影响,把这两种情况列出来就好了。
\(dp_{u,0,0}\gets min_{v\in son[u]}(dp_{v,0,a_v}+dp_{u,0,0},dp_{v,1,a[v]}+dp_{u,0,1})\)
前者是不受影响,后者是受影响。
同理我们接着列就行了。
\(dp_{u,0,1}\gets min_{v\in son[u]}(dp_{v,0,a_v}+dp_{u,0,1},dp_{v,1,a[v]}+dp_{u,0,0})\)
\(dp_{u,1,0}\gets min_{v\in son[u]}(dp_{v,0,(1-a_v)}+dp_{u,1,0},dp_{v,1,(1-a[v])}+dp_{u,1,1})\)
\(dp_{u,1,1}\gets min_{v\in son[u]}(dp_{v,0,(1-a_v)}+dp_{u,1,1},dp_{v,1,(1-a[v])}+dp_{u,1,0})\)
打比较长的 Latex 能力较弱,应该没什么大问题了。
考虑怎么初始化,实际很简单,初始化什么都不动和修改一下就行,其它情况等着转移上来。
就是 dp[u][0][0]=0, dp[u][1][1]=1, dp[u][1][0]=dp[u][0][1]=0x3f3f3f3f;
之后还需要注意我们的转移可能会出现问题,直接这么写会出环。
每一次进行转移的时候我们使用 tmp[2][2] 存一下 dp[u][2][2] 的值,里边用这个进行转移就没问题了。
代码↓
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MN=1e6+116;
struct Node{
int nxt, to;
}node[MN];
int head[MN], tottt;
void insert(int u, int v){
node[++tottt].to=v;
node[tottt].nxt=head[u];
head[u]=tottt; return;
}
int a[MN], n, dp[MN][2][2], ans;
void dfs(int u, int father){
bool isleaf=true;
dp[u][0][0]=0; dp[u][1][1]=1;
dp[u][1][0]=1e10;
dp[u][0][1]=1e10;
for(int i=head[u];i;i=node[i].nxt){
int v=node[i].to;
if(v==father) continue;
dfs(v,u); isleaf=false;
}
for(int i=head[u];i;i=node[i].nxt){
int v=node[i].to;
if(v==father) continue;
int tmp[2][2];
tmp[0][0]=dp[u][0][0];
tmp[0][1]=dp[u][0][1];
tmp[1][1]=dp[u][1][1];
tmp[1][0]=dp[u][1][0];
dp[u][0][0]=min(tmp[0][0]+dp[v][0][a[v]],tmp[0][1]+dp[v][1][a[v]]);
dp[u][0][1]=min(tmp[0][1]+dp[v][0][a[v]],tmp[0][0]+dp[v][1][a[v]]);
dp[u][1][0]=min(tmp[1][0]+dp[v][0][(1-a[v])],tmp[1][1]+dp[v][1][(1-a[v])]);
dp[u][1][1]=min(tmp[1][1]+dp[v][0][(1-a[v])],tmp[1][0]+dp[v][1][(1-a[v])]);
}
if(u==1){
ans=min(dp[1][0][a[1]],dp[1][1][a[1]]);
}
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin>>n;
for(int i=1,u,v; i<n; ++i){
cin>>u>>v; insert(u,v); insert(v,u);
}
for(int i=1; i<=n; ++i) cin>>a[i];
dfs(1,1);
if(ans>=1e10) cout<<"impossible\n";
else cout<<ans<<'\n';
return 0;
}

浙公网安备 33010602011771号