首页 > 其他分享 >Solution -「HDU」Ridiculous Netizens

Solution -「HDU」Ridiculous Netizens

时间:2023-09-22 18:11:29浏览次数:44  
标签:rt sz HDU int rep MN Netizens Ridiculous 100

Desc.

  给定一棵 \(N\) 个节点无根树,找出满足以下条件的集合 \(S\) 的数量:

  • \(S \subseteq \{1,\dots,n\}\);
  • \(S\) 的导出子图联通;
  • \(\displaystyle\prod_{v \in S} a_v \leqslant M\)。

Sol.

  点分治,统计包括当前分治中心的集合数量,如果从子树的角度入手会发现并不好做——合并这一步就卡死了。考虑以 DFN 为状态,设 \(f(i,j)\) 表示在子树中 DFN 序排后 \(i\) 个节点中选出了乘积为 \(j\) 的集合。这个状态实际上是很浪费空间的,那么使用根号分治,另令 \(g(i, j)\) 表示乘积 \(\frac{M}{j}\) 时的方案数,这样就开得下了。

const int MN = 2e3, B = 1e3;
int n, m, a[MN + 100], f[MN + 100][B + 100], g[MN + 100][B + 100];
int sz[MN + 100], res, rev[MN + 100], Time, mxsb[MN + 100], rt;
bool vis[MN + 100];
vvi grp;
void getsz(int u, int Fu) {
    sz[u] = 1; for (int v : grp[u]) if (v != Fu && !vis[v]) getsz(v, u), sz[u] += sz[v];
}
void getrt(int u, int Fu, int all) {
    mxsb[u] = all-sz[u];
    for (int v : grp[u]) if (v != Fu && !vis[v]) {
        getrt(v, u, all); chkmax(mxsb[u], sz[v]);
    }
    if (rt == 0 || mxsb[u] < mxsb[rt]) rt = u;
}
void dfs(int u, int Fu) {
    rev[Time++] = u;
    for (int v : grp[u]) if (v != Fu && !vis[v]) dfs(v, u);
}
void solve(int u) {
    rt = 0; getsz(u, n); getrt(u, n, sz[u]); vis[rt] = 1; Time = 0; dfs(rt, n); getsz(rt, n);
    rep(Time+1) {
        memset(f[i], 0, sizeof f[i]);
        memset(g[i], 0, sizeof g[i]);
    }
    f[Time][1] = 1;
    drep(i,Time-1,0) {
        int w = a[rev[i]];
        // Putting @i into the component.
        rep(j,1,B+1) {
            if (j <= B / w) add_eq(f[i][j * w], f[i+1][j]);
            else if ((m / j) / w > 0) add_eq(g[i][(m / j) / w], f[i+1][j]);
        }
        rep(j,w,B+1) add_eq(g[i][j/w], g[i+1][j]);
        // Putting @i out of the component, skipping its subtree.
        rep(j,1,B+1) {
            add_eq(f[i][j], f[i+sz[rev[i]]][j]);
            add_eq(g[i][j], g[i+sz[rev[i]]][j]);
        }
    }
    rep(i,1,min(B, m)+1) add_eq(res, add(f[0][i], g[0][i]));
    rep(i,min(B, m),B+1) add_eq(res, g[0][i]);
    sub_eq(res, 1);
    for (int v : grp[rt]) if (!vis[v]) solve(v);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(nullptr);
    cin >> n >> m;
    grp = vvi(n);
    rep(n) cin >> a[i];
    rep(n-1) {int u,v; cin >> u >> v; u--; v--; grp[u].pb(v); grp[v].pb(u);}
    solve(0); cout << res << "\n";
}

标签:rt,sz,HDU,int,rep,MN,Netizens,Ridiculous,100
From: https://www.cnblogs.com/orchid-any/p/17723086.html

相关文章

  • HDU 4609
    题目链接description给定一个长度为\(n\)的序列\(A\),元素值域大小为\(10^5\)。求从中任选三个不同位置的元素,以它们的值为三边能够成三角形的概率。solution设有\(cnt\)种选三个不同的元素构成三角形的方案,则答案显然为\(\dfrac{6cnt}{n(n-1)(n-2)}\)。\(a,b,c(a\leq......
  • HDU 1054 Strategic Game 树形DP/二分图匹配
    第一次写博文,想了半天就拿一道dp/graph的题作为处作吧此题有两种常见解法(题意比较简单,就不赘述)1.二分图最大匹配       此题等价于问一棵树中最小点覆盖数。树形结构可以把它看做是一个二分图,一个点集为奇数层,另一个点集为偶数层,显然满足二分图定义,可以套用求二分图最小点......
  • hdu 4712 Hamming Distance-----随机
    计算出二进制数中有多少个1:数据范围太大,想到可以随机如果你在第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand()。------百度rand#include<cstdio>#include<cstring>#include<algorithm>#include<time.h>usingnamespacestd;constintN=1e5+10......
  • hdu 4705 Y
    dfs1.要#pragmacomment(linker,"/STACK:16777216")2.扩栈要vc++编译环境3.不能用%lld,要用%I64d,无语。。#pragmacomment(linker,"/STACK:16777216")//手动扩栈#include<stdio.h>#include<string.h>#include<stdlib.h>#include<vector>using......
  • hdu-3926-Hand in Hand-并查集
    判断两个图是否同构。。用了并查集。。#include<stdio.h>#include<string.h>#include<stdlib.h>#include<algorithm>#include<queue>#include<stack>usingnamespacestd;#definelllonglongintn,m;structnode{ intfu; intsum; intf......
  • HDU 2955 Robberies
    01背包银行总钱数==容量V概率可以算安全的概率p=1-p;#include<stdio.h>#include<string.h>#include<algorithm>usingnamespacestd;doublepp,p[10001],f[10001];intv[10001];intmain(){ intt; scanf("%d",&t); while(t--){ intn,j,i,k,sum......
  • hdu 1372 Knight Moves 骑士的移动 bfs--马走日
    #include<stdio.h>#include<string.h>#include<queue>usingnamespacestd;charss[3],ee[3];intx1,y1,x2,y2;structpos{intx,y,step;}sta,end;intf[10][10];intdir[8][2]={1,2,1,-2,-1,2,-1,-2,2,1,2,-1,-2,1,-2,-1};boolfan......
  • 二叉树 遍历 hdu-1710-Binary Tree Traversals
    给出二叉树的前序遍历和中序遍历,求后序遍历。。 算法:由前序遍历的第一个元素可确定左、右子树的根节点,参照中序遍历又可进一步确定子树的左、右子树元素。如此递归地参照两个遍历序列,最终构造出二叉树。 由前序和中序结果求后序遍历结果树的遍历: 给你一棵树的先......
  • hdu1400/acwing 291 Mondriaan's Dream
    题意描述:给定一块n*m的区域,用1*2的长方形填充,长方形可以横着或竖着摆,问一共有多少种填充方案具体思路:题意没什么好说的,简单易懂,很经典的一类状态压缩问题(在棋盘中求填充方案)。观察数据,满足n,m都比较小,但是搜索的复杂度大到无法接受,考虑使用状态压缩求解此类问题......
  • [HDU4117] GRE
    RecentlyGeorgeispreparingfortheGraduateRecordExaminations(GREforshort).Obviouslythemostimportantthingisrecitingthewords.NowGeorgeisworkingonawordlistcontaining\(N\)words.Hehassopooramemorythatitistoohardforhim......