衢州集训Day-5模拟赛

昨天偷懒了。。。。。。。。。。

今天的题很妙啊

T-1

题目描述
给定一个 个节点的树,节点的标号为 ,边的标号为 。每条边 连接节点 和 ,并且有
一个权值 。你可以进行如下的操作若干次。
选择一条简单路径以及一个非负整数 ,然后对于每条属于这条路径的边,将它的权值异或上 。
你的目标是让所有边的权值变成 ,同时,最小化操作的次数。
输入格式
第一行一个正整数 。
接下来 行,每行三个非负整数 ,表示边 连接 ,权值为 。
输出格式
输出一个数,最小的操作次数。

对于%100 的数据,n<=1e5,边权<15 ,保证输入的是一棵树

题解:

由于路径的话很难操作。所以我们把路径变成点!定义一个点的点权为与其相连的边xor起来

然后贪心两两先练掉,再dp就可以了。。。。

```cpp

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int f[(1<<16)+5];
#define inf 0x7f7f7f7f
inline int DP(int s){
if(!s) return 0;if(f[s]) return f[s];int ret=inf,tmp;
for(int i=1;i<16;++i)
if(s&(1<<i))
for(int j=1,k;j<16;++j)
if(i!=j&&(s&(1<<j)))
k=i^j,tmp=(s&(1<<k))?1:0,ret=min(ret,DP(s^(1<<i)^(1<<j)^(1<<k))+1+tmp);
return f[s]=ret;
}
int a[100005],S=0,ans=0;
int main()
{
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
int n=read();
for(int i=1;i<n;++i){int x=read(),y=read(),z=read();a[x]^=z;a[y]^=z; }
for(int i=0;i<n;++i) if(a[i]) ((S>>a[i])&1)?(S^=1<<a[i],++ans):S^=1<<a[i];
// cout<<DP(S)<<endl;
return printf("%d\n",DP(S)+ans),0;
}

```cpp

posted @ 2019-02-17 15:18  Cseller  阅读(136)  评论(0编辑  收藏  举报