Problem Description

Mr. Bread has a tree T with n vertices, labeled by 1,2,…,n. Each vertex of the tree has a positive integer value wi.

The value of a non-empty tree T is equal to w1×w2×⋯×wn. A subtree of T is a connected subgraph of T that is also a tree.

Please write a program to calculate the number of non-empty subtrees of T whose values are not larger than a given number m.

Input

The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.

In each test case, there are two integers n,m(1≤n≤2000,1≤m≤106) in the first line, denoting the number of vertices and the upper bound.

In the second line, there are n integers w1,w2,…,wn(1≤wi≤m), denoting the value of each vertex.

Each of the following n−1 lines contains two integers ui,vi(1≤ui,vi≤n,ui≠vi), denoting an bidirectional edge between vertices ui and vi.

Output

For each test case, print a single line containing an integer, denoting the number of valid non-empty subtrees. As the answer can be very large, output it modulo 10^9+7.

Sample Input

1
5 6
1 2 1 2 3
1 2
1 3
2 4
2 5

Sample Output

14
题意:
一棵无根树,每个点有权值,询问有多少个联通子图的权值的积等于m 思路
https://www.cnblogs.com/hua-dong/p/11320013.html
考虑对某点,联通块要么经过它要么不经过它 ——> 点分治
对于经过该点的用dp求解
在dfs序上dp,类似于树形依赖背包
dp[i][j]表示 dfs序i之后的乘积为j的方案数
可知 dp[i][j]=(dp[i+1][j/a[dfn[i]]]+dp[i+son[i]][j]) //当前点选/不选
但第二维为m不可行
考虑把<sqrt(M)的和大于sqrt(M)的分开保存,那么前者就是正常的背包,表示当前乘积;后者可以看成以后还可以取多少
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int N=1e5+;
const int p=1e9+;
int T,n,m,cnt,sum,root,tim,ans;
struct orz{
int v,nex;}e[N*];
int a[N],last[N],son[N],f[N],dfn[N],dp1[N][],dp2[N][];
bool vis[N];
void add(int x,int y)
{
cnt++;
e[cnt].v=y;
e[cnt].nex=last[x];
last[x]=cnt;
}
void getroot(int x,int fa)
{
son[x]=; f[x]=;
for (int i=last[x];i;i=e[i].nex)
{
if (e[i].v==fa || vis[e[i].v]) continue;
getroot(e[i].v,x);
son[x]+=son[e[i].v];
f[x]=max(f[x],son[e[i].v]);
}
f[x]=max(f[x],sum-son[x]);
if (f[x]<f[root]) root=x;
}
void dfs(int x,int fa)
{
dfn[++tim]=x; son[x]=;
for (int i=last[x];i;i=e[i].nex)
{
if (e[i].v==fa || vis[e[i].v]) continue;
dfs(e[i].v,x);
son[x]+=son[e[i].v];
}
}
void cal()
{
int mm=sqrt(m);
for (int i=;i<=tim+;i++)
{
memset(dp1[i],,sizeof(dp1[i]));
memset(dp2[i],,sizeof(dp2[i]));
}
dp1[tim+][]=;
for (int i=tim;i>=;i--)
{
int x=a[dfn[i]];
for (int j=;j<=min(mm,m/x);j++)
{
int k=j*x;
if (k<=mm) dp1[i][k]=(dp1[i][k]+dp1[i+][j])%p;
else dp2[i][m/k]=(dp2[i][m/k]+dp1[i+][j])%p;
}
for (int j=x;j<=mm;j++)
{
dp2[i][j/x]=(dp2[i][j/x]+dp2[i+][j])%p;
}
for (int j=;j<=mm;j++)
{
dp1[i][j]=(dp1[i][j]+dp1[i+son[dfn[i]]][j])%p;
dp2[i][j]=(dp2[i][j]+dp2[i+son[dfn[i]]][j])%p;
}
}
for (int i=;i<=mm;i++)
{
ans=(ans+dp1[][i])%p;
ans=(ans+dp2[][i])%p;
}
ans=(ans-+p)%p;
}
void work(int x)
{
//cout<<x<<endl;
vis[x]=; tim=;
dfs(root,); //for (int i=1;i<=tim;i++) cout<<dfn[i]<<' '; cout<<endl;
cal();
for (int i=last[x];i;i=e[i].nex)
{
if (vis[e[i].v]) continue;
sum=son[e[i].v];
root=;
getroot(e[i].v,root);
work(root);
}
}
void init()
{
cnt=; ans=;
for (int i=;i<=n;i++) last[i]=,vis[i]=;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
for (int i=;i<=n;i++) scanf("%d",&a[i]);
int x,y;
for (int i=;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
sum=n; f[]=inf;
getroot(,);
work(root);
printf("%d\n",ans);
}
return ;
}


杭电多校第六场-J-Ridiculous Netizens的更多相关文章

  1. 2017杭电多校第六场1008 Kirinriki

    传送门 Kirinriki Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) To ...

  2. 2017杭电多校第六场03Inversion

    传送门 Inversion Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) To ...

  3. [2019杭电多校第六场][hdu6638]Snowy Smile(维护区间最大子段和)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6638 题意为在一个平面上任意选择一个长方形,使得长方形内点权和最大. 因为长方形可以任意选择,所以上下 ...

  4. 2019杭电多校第六场hdu6638 Snowy Smile(线段树+枚举)

    Snowy Smile 题目传送门 解题思路 先把y离散化,然后把点按照x的大小进行排序,我们枚举每一种x作为上边界,然后再枚举其对应的每一种下边界.按照这种顺序插入点,这是一个压维的操作,即在线段树 ...

  5. 2018杭电多校第六场1009(DFS,思维)

    #include<bits/stdc++.h>using namespace std;int a[100010];char s[20];int zhiren[100010];vector& ...

  6. 2017杭电多校第六场1011Classes

    传送门 Classes Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tota ...

  7. [2019杭电多校第六场][hdu6641]TDL

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6641 题意为求出最小的n,满足(f(n,m)-n)^n=k,其中f(n,m)为第m大的x,其中x满足g ...

  8. [2019杭电多校第六场][hdu6635]Nonsense Time

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6635 题意是说一开始所有数都冻结,第i秒会解冻第ki个数,求每秒状态下的最长上上升子序列长度. 这种题 ...

  9. 可持久化线段树的学习(区间第k大和查询历史版本的数据)(杭电多校赛第二场1011)

    以前我们学习了线段树可以知道,线段树的每一个节点都储存的是一段区间,所以线段树可以做简单的区间查询,更改等简单的操作. 而后面再做有些题目,就可能会碰到一种回退的操作.这里的回退是指回到未做各种操作之 ...

随机推荐

  1. 浏览器HTML自带懒加载技术

    对于目前的图片懒加载,我们一般采用的是通过第三方库或懒加载库来实现,但是该方式的显著问题就是,必须按顺序执行: 1.加载初始的 HTML 响应内容 2.加载懒加载库 3.加载图片 假如浏览器能直接支持 ...

  2. LeetCode Array Easy 283. Move Zeroes

    Description Given an array nums, write a function to move all 0's to the end of it while maintaining ...

  3. 【记录】解决前端form表单回车禁止刷新页面

    最近弄前端 有form表单的情况下 按回车会自动刷新当前页面. 现记录解决方案如下: 1.去掉表单 2.不要让表单中只有一个文本框(增加一个隐藏的文本框就行) 3.以上两点都不想使用,那么就还可以在表 ...

  4. php递归无限分类、根据子类获取所有顶类

    //递归无限分类树 public static function diGui($data, $pid) { $arr = collect([]); if (empty($data)) { return ...

  5. java模式-----单例模式

    什么是单例设计模式? 单例模式,是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例. 类结构 ...

  6. 【架构】Linux的架构(architecture)

    最内层是硬件,最外层是用户常用的应用,比如说firefox浏览器,evolution查看邮件,一个计算流体模型等等.硬件是物质基础,而应用提供服务.但在两者之间,还要经过一番周折. 还记得Linux启 ...

  7. 【LeetCode 30】串联所有单词的子串

    题目链接 [题解] 开个字典树记录下所有的单词. 然后注意题目的已知条件 每个单词的长度都是一样的. 这就说明不会出现某个字符串是另外一个字符串的前缀的情况(除非相同). 所以可以贪心地匹配(遇到什么 ...

  8. iOS 获取self类型

    类型转换快速写法 typeof(self) bself = self; 版权声明:本文为博主原创文章,未经博主允许不得转载.

  9. python进阶:类和对象

    @修饰符:将被修饰的函数作为参数,运行修饰函数 实例方法: 静态方法:@staticmethod 类方法:@classmethod 自省:通过一定的机制查询到对象的内部结构 序列类: 列表推导式(例表 ...

  10. MySQL 5.7配置文件

    原文:http://www.voidcn.com/article/p-zrikccdi-hr.html # MySql5.7配置文件my.cnf设置[client]port = 3306socket ...