树上路径的f(u,v)=路径上所有点的乘积。

树上每个点的权值都是由给定的k个素数组合而成的,如果f(u,v)是立方数,那么就说明f(u,v)是可行的方案。

问有多少种可行的方案。

f(u,v)可是用状态压缩来表示,因为最多只有30个素数, 第i位表示第i个素数的幂,那么每一位的状态只有0,1,2因为3和0是等价的,所以用3进制状态来表示就行了。

其他代码就是裸的树分。

另外要注意的是,因为counts函数没有统计只有一个点的情况,所以需要另外统计。

 #pragma warning(disable:4996)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <algorithm>
#include <iostream>
#include <string>
#include <functional>
#include <unordered_map>
const int INF = << ;
typedef __int64 LL;
/*
用三进制的每一位表示第i个素数的幂
如果幂都是0,那么说明是立方
*/
const int N = + ;
std::vector<int> g[N];
std::unordered_map<LL, int> mp;
struct Node
{
int sta[];
}node[N];
LL prime[];
std::vector<Node> dist;
int n, k;
int size[N], vis[N], total, root, mins;
LL _3bit[];
void init()
{
_3bit[] = ;
for (int i = ;i <= ;++i)
_3bit[i] = _3bit[i - ] * ;
}
void getRoot(int u, int fa)
{
int maxs = ;
size[u] = ;
for (int i = ;i < g[u].size();++i)
{
int v = g[u][i];
if (v == fa || vis[v]) continue;
getRoot(v, u);
size[u] += size[v];
maxs = std::max(maxs, size[v]);
}
maxs = std::max(maxs, total - size[u]);
if (mins > maxs)
{
mins = maxs;
root = u;
}
}
void getDis(int u, int fa, Node d)
{
dist.push_back(d);
for (int i = ;i < g[u].size();++i)
{
int v = g[u][i];
if (v == fa || vis[v]) continue;
Node tmp;
for (int j = ;j < k;++j)
tmp.sta[j] = (d.sta[j] + node[v].sta[j]) % ;
getDis(v, u, tmp);
}
}
LL counts(int u)//计算经过u点的路径
{
mp.clear();
mp[] = ;
LL ret = ;
for (int i = ;i < g[u].size();++i)
{
int v = g[u][i];
if (vis[v]) continue;
dist.clear();
getDis(v, u, node[v]);
for (int j = ;j < dist.size();++j)
{
LL sta = ;
for (int z = ;z < k;++z)
{
sta += ( - (node[u].sta[z] + dist[j].sta[z]) % ) % * _3bit[z];
}
ret += mp[sta];
}
for (int j = ;j < dist.size();++j)
{
LL sta = ;
for (int z = ;z < k;++z)
sta += dist[j].sta[z] * _3bit[z];
mp[sta]++;
}
}
return ret;
}
LL ans;
void go(int u)
{
vis[u] = true;
ans += counts(u);
for (int i = ;i < g[u].size(); ++i)
{
int v = g[u][i];
if (vis[v]) continue;
total = size[v];
mins = INF;
getRoot(v, u);
go(root);
} }
int main()
{
int u, v;
LL x;
init();
while (scanf("%d%d", &n, &k) != EOF)
{
for (int i = ;i < k;++i)
scanf("%I64d", &prime[i]);
ans = ;
for (int i = ;i <= n;++i)
{
g[i].clear();
vis[i] = ;
scanf("%I64d", &x);
memset(node[i].sta, , sizeof(node[i].sta));
int tmp = ;
for (int j = ;j <k;++j)
{ while (x%prime[j] == && x)
{
node[i].sta[j]++;
x /= prime[j];
}
node[i].sta[j] %= ;
if (node[i].sta[j] != )tmp++;
}
if (tmp == )//统计只有一个点的
ans++;
}
for (int i = ;i < n;++i)
{
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
total = n;
mins = INF;
getRoot(, -);
go(root);
printf("%I64d\n", ans);
}
return ;
}

hdu4670(树上点分治+状态压缩)的更多相关文章

  1. HDU 5977 Garden of Eden (树分治+状态压缩)

    题意:给一棵节点数为n,节点种类为k的无根树,问其中有多少种不同的简单路径,可以满足路径上经过所有k种类型的点? 析:对于路径,就是两类,第一种情况,就是跨过根结点,第二种是不跨过根结点,分别讨论就好 ...

  2. topcoder-srm701-div2-900 博弈\计算二进制位1的个数\dp\状态压缩

    借用一下qls翻译过来的题面  现在有 n 个石子,A 和 B 轮流取石子,A先,每次最多可以取 m 个石子,取到最后一个石子的人获胜,但是某个人如果取完石子时候剩余石子数的二进制表示中有奇数个1,这 ...

  3. POJ 3691 (AC自动机+状态压缩DP)

    题目链接:  http://poj.org/problem?id=3691 题目大意:给定N个致病DNA片段以及一个最终DNA片段.问最终DNA片段最少修改多少个字符,使得不包含任一致病DNA. 解题 ...

  4. hdu 4057(ac自动机+状态压缩dp)

    题意:容易理解... 分析:题目中给的模式串的个数最多为10个,于是想到用状态压缩dp来做,它的状态范围为1-2^9,所以最大为2^10-1,那我们可以用:dp[i][j][k]表示长度为i,在tri ...

  5. POJ 2777.Count Color-线段树(区间染色+区间查询颜色数量二进制状态压缩)-若干年之前的一道题目。。。

    Count Color Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 53312   Accepted: 16050 Des ...

  6. [BZOJ 4455] [ZJOI 2016] 小星星 (树形dp+容斥原理+状态压缩)

    [BZOJ 4455] [ZJOI 2016] 小星星 (树形dp+容斥原理+状态压缩) 题面 给出一棵树和一个图,点数均为n,问有多少种方法把树的节点标号,使得对于树上的任意两个节点u,v,若树上u ...

  7. 状态压缩动态规划(状压DP)详解

    0 引子 不要999,也不要888,只要288,只要288,状压DP带回家.你买不了上当,买不了欺骗.它可以当搜索,也可以卡常数,还可以装B,方式多样,随心搭配,自由多变,一定符合你的口味! 在计算机 ...

  8. POJ 3254. Corn Fields 状态压缩DP (入门级)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9806   Accepted: 5185 Descr ...

  9. HDU 3605:Escape(最大流+状态压缩)

    http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意:有n个人要去到m个星球上,这n个人每个人对m个星球有一个选择,即愿不愿意去,"Y" ...

随机推荐

  1. iOS基本控制-UINavigationController 传统的价值观,代理传统价值观,正向传统价值观,反传统的价值观

    /*        程序过程:  1.创建一个根视图,一个二级视图  2,根视图NavigationItem.title = Root 二级视图NavigationItem.title = Secon ...

  2. 可以根据柜子内表取出所有的柜子信息的BAPI函数

    DATA: gt_hunumbers TYPE STANDARD TABLE OF bapihunumber,      gt_huitem  TYPE STANDARD TABLE OF bapih ...

  3. Android开发按返回键应用后台运行

    @Override  public boolean onKeyDown(int keyCode, KeyEvent event) {   if (keyCode == KeyEvent.KEYCODE ...

  4. 深入分析redis cluster 集群

    深入分析redis cluster 集群安装配置详解 下面小编来为各位介绍一篇深入分析redis cluster 集群安装配置详解,如果你希望做数据库集群就可以来看看此文章的哦. http://rub ...

  5. navicat for mysql 显示中文乱码解决办法

      最近遇到一个问题,用navicat for mysql 打开数据库时全都显示的是乱码(在用程序代码插入数据之前确保字符不是乱码),遇到问题就的寻求解决之道,百度了好长时间也没解决,网上那些解决办法 ...

  6. 解决xShell4某些情况下按删除键会输出^H的问题

    当我们用Xshell登录进入linux后,在普通模式下,对输入进行删除等操作没有问题. 而在执行中,按delete,backspace键时会产生^H等乱码问题. 这是由于编码不匹配的问题. 解决方法: ...

  7. ZOJ 1171 Sorting the Photos

    1. 题目描述 给你一叠照片,有的正面朝上,有的反面朝上,朝上的用字母U,朝下的用字母D 可以从一个位置开始到最顶端,把这一叠拿出来,反转,然后再放回那一叠照片上面. 试求出最少的翻转次数,使所有的照 ...

  8. C++ 指针—02 指针与引用的对照

    ★同样点: ●都是地址的概念: 指针指向一块内存,它的内容是所指内存的地址:而引用则是某块内存的别名. ★不同点: ●指针是一个实体,而引用仅是个别名: ●引用仅仅能在定义时被初始化一次,之后不可变: ...

  9. activity_main.xml: java.lang.NullPointerException

    1.错误描写叙述 eclipse.buildId=4.4.0.I20140606-1215 java.version=1.7.0_67 java.vendor=Oracle Corporation B ...

  10. Tiny Mapper是一个.net平台开源的对象映射组件

    NET平台开源项目速览(14)最快的对象映射组件Tiny Mapper   阅读目录 1.Tiny Mapper基本介绍 2.Tiny Mapper 基本使用 3.Tiny Mapper 指定配置使用 ...