日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AT3913-XOR Tree【状压dp】

發(fā)布時間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AT3913-XOR Tree【状压dp】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/AT3913


題目大意

給出一棵有邊權的樹,你每次可以選擇一條鏈讓所有的邊異或上同一個值,求最少的操作次數使得所有邊的權值都為000。

2≤n≤105,0≤w<162\leq n\leq 10^5,0\leq w<162n105,0w<16


解題思路

一條邊的權值可以視為連接的兩個點的權值異或,那么我們就可以把邊邊為點權了。

而鏈的異或就可以變成首尾兩個點同時異或上一個值。

那么問題就變?yōu)榱私onnn個數字你每次可以讓兩個同時異或上任意一個數,求最少操作次數使得它們都變?yōu)?span id="ozvdkddzhkzd" class="katex--inline">000。

那么顯然一樣的我們直接異或掉最優(yōu),那么現在就只剩下最多161616個不同的數了。

考慮狀壓dpdpdp,注意到如果一個集合能夠操作到000那么這個集合肯定有所有數字的異或和為000,因為無論怎么操作序列的異或和都不會變。

那么理論上如果有xxx個數字,那么我們的操作次數上限是x?1x-1x?1,但是如果我們能把集合SSS分成兩個集合T,S?TT,S-TT,S?T且這兩個集合的異或和都為000,那么就變成了x?2x-2x?2,也就是最小的值在我們盡量分最多集合得到。

fSf_SfS?表示SSS最多分成多少個集合,然后O(316)O(3^{16})O(316)轉移就好了。

時間復雜度:O(n+316)O(n+3^{16})O(n+316)


code

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+10,M=16; int n,ans,a[N],v[M],c[1<<M],f[1<<M]; int main() {scanf("%d",&n);for(int i=1,x,y,w;i<n;i++){scanf("%d%d%d",&x,&y,&w);a[x]^=w;a[y]^=w;}for(int i=0;i<n;i++)v[a[i]]++;int MS=(1<<16);memset(f,0xcf,sizeof(f));for(int s=1;s<MS;s++)for(int i=0;i<16;i++)if((s>>i)&1){c[s]=c[s-(1<<i)]^i;if(!c[s])f[s]=0;break;}int S=0;f[0]=0;for(int i=1;i<16;i++)ans+=(v[i]+1)/2,S|=((v[i]&1)<<i);if(!S)return printf("%d\n",ans)&0;for(int s=1;s<MS;s++){if(c[s])continue;for(int t=(s-1)&s;t>=(s^t);t=(t-1)&s)f[s]=max(f[s],f[t]+f[s^t]+1);}printf("%d\n",ans-f[S]-1);return 0; } /* 4 0 1 5 1 2 3 2 3 5 */

總結

以上是生活随笔為你收集整理的AT3913-XOR Tree【状压dp】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。