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. setquota - 设置磁盘配额或时间限制

    SYNOPSIS(总览) setquota [ -u | -g ] filesystem-name block-soft block-hard inode-soft inode-hard name.. ...

  2. dotNET面试(二)

    值类型与引用类型 1.值类型和引用类型的区别? 值类型包括简单类型.结构体类型和枚举类型,引用类型包括自定义类.数组.接口.委托等. 赋值方式:将一个值类型变量赋给另一个值类型变量时,将复制包含的值. ...

  3. dotNET面试(一)

    1.列举ASP.NET 页面之间传递值的几种方式. 1).使用QueryString, 如....?id=1; response. Redirect().... 2).使用Session变量 3).使 ...

  4. Node.js require 方法

    Node.js 中存在 4 类模块(原生模块和3种文件模块),尽管 require 方法极其简单,但是内部的加载却是十分复杂的,其加载优先级也各自不同

  5. hdu4857 拓扑排序

    题目大意: 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前. 同时,社会是不平等的,这些 ...

  6. 2018/8/26学习Mysql笔记

    SELECT * FROM product; #.基本增删改查 #新增 #需求:添加一条数据到产品表 产品名称为苹果手机 卖价为5000 ); #删除 #需求:删除产品表中id=20的数据 ; #需求 ...

  7. 【leetcode】207. Course Schedule

    题目如下: There are a total of n courses you have to take, labeled from 0 to n-1. Some courses may have ...

  8. openwrt配置内核,加载air720 4G模块的USB串口设备

    1,进入openwrt源码包,键入 make menuconfig 2,配置如下 kernel modules  ---> USB Support---> <*> kmod-u ...

  9. QTcpSocket发送结构体

    我需要发送的结构体 struct NetDataHeader_t { int nDataType; int nDataSize; }; struct NetDataBase_t { NetDataHe ...

  10. pic16f877a的AD实验学习

    一.主函数 //采集AD值 #include <pic.h> #include "ad.h" #include "usart.h" __CONFIG ...