树上路径的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. css Gradients(渐变)

    渐变分为4类 1:线性渐变(Linear Gradients)- 向下/向上/向左/向右/对角方向 2:径向渐变(Radial Gradients)- 由它们的中心定义 3:对角渐变 4:角度渐变 以 ...

  2. 【Unity3D】【NGUI】UILabel

    原文:http://www.tasharen.com/forum/index.php?topic=6706.0 NGUI讨论群:333417608 概述 UILabel是用来显示文本的脚本,继承自UI ...

  3. Qt制作应用插件

    在Qt下,插件有两种形式,一种是用于QtCreator下,扩展IDE功能.另一种是用于扩展开发者的应用.本文要讲的是后者. 定义一个纯虚类作为插件接口 #include <QtPlugin> ...

  4. Codeforces Round #249 (Div. 2) A B

    C好像就是个模拟.D 是个编码复杂度大的,可是好像也就是枚举三角形,我这会儿准备区域赛,尽量找点思维难度大的,所以昨晚A B 还是去做区域赛题吧..... B 也有点意思 贪心 题意:交换相邻两个位的 ...

  5. 一个用 C 语言写的迷你版 2048 游戏,仅仅有 500个字符

    Jay Chan 用 C 语言写的一个迷你版 2048 游戏,仅仅有 487 个字符. 来围观吧 M[16],X=16,W,k;main(){T(system("stty cbreak&qu ...

  6. [Android学习笔记]捕获物理回退事件

    物理回退按钮默认情况下是finish当前activity,返回上一个activity 当需要获取物理回退按钮的相应事件时候,可以这么做 步骤如下: 1.override当前activity的onKey ...

  7. [Android]ADT Run时候报错:The connection to adb is down, and a severe error has occured

    The connection to adb is down, and a severe error has occured. 之 ..\sdk\platform-tools\adb.exe and c ...

  8. hdu3790最短路径问题 (用优先队列实现的)

    Problem Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的.   Inp ...

  9. 定义自己的布局RelativeLayout 绘制网格线

    在Android画线必须由一个载体,无论是控制,无论是布局.实际上它们是从继承View.由画线的方式自己的控制或布局的定义是最常见的. 以下是在其定义中的小样本实现RelativeLayout绘制网络 ...

  10. HDU 2255 奔小康,赚钱(KM算法模板)

    解决问题的思路: 二部图,正确的匹配,卡费用流,使用KM算法. #include <cstring> #include <algorithm> #include <cst ...