HDU 5909 FWT 加速集合异或

【题意】


Byteasar有一棵nn个点的无根树,节点依次编号为11nn,其中节点ii的权值为v_ivi。

定义一棵树的价值为它所有点的权值的异或和。

现在对于每个[0,m)[0,m)的整数kk,请统计有多少TT的非空连通子树的价值等于kk。

一棵树TT的连通子树就是它的一个连通子图,并且这个图也是一棵树。

【解题思路】 树形DP。DP[i][j]代表以i为根,异或结果为j的方案数,那么我们可以写出树形DP的大致结构如下:


HDU 5909 FWT 加速集合异或_第1张图片

这段代码里的solve,就是求两个集合异或的结果,明显我们暴力做是O(m * m)的, 这里暴力做,加一些优化,例如读入挂等是可以莽过去这个题目的。但是这里有个更经典的加速集合异或的方法,FWT。复杂度可以降为O(m * logm),我给出FWT的模板


const int rev = (mod + 1) >> 1; // FWT

void FWT(int a[],int n)
{
    for(int d=1;d

这个FWT模板的是非递归的形式,常数比递归少很多,还是可以学习的。


给出完整AC代码


//
//Created by BLUEBUFF 2016/1/10
//Copyright (c) 2016 BLUEBUFF.All Rights Reserved
//

#pragma comment(linker,"/STACK:102400000,102400000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  //isstringstream
#include 
#include 
using namespace std;
//using namespace __gnu_pbds;
typedef long long LL;
typedef pair pp;
#define REP1(i, a, b) for(int i = a; i < b; i++)
#define REP2(i, a, b) for(int i = a; i <= b; i++)
#define REP3(i, a, b) for(int i = a; i >= b; i--)
#define CLR(a, b)     memset(a, b, sizeof(a))
#define MP(x, y)      make_pair(x,y)
template inline void getmax(T1 &a, T2 b) { if (b>a)a = b; }
template inline void getmin(T1 &a, T2 b) { if (b> 1; // FWT
const double PI = acos(-1);
//head

//dp[u][i] 表示 u 为根的树,异或后得到i的方案数
int val[maxn], dp[maxn][maxn], ans[maxn], temp[maxn];
int n, m;
vector  G[maxn * 2];

void FWT(int a[],int n)
{
    for(int d=1;d


你可能感兴趣的:(ACM/ICPC_FWT)