zoukankan      html  css  js  c++  java
  • BZOJ4401:块的计数(乱搞)

    Description

    小Y最近从同学那里听说了一个十分牛B的高级数据结构——块状树。听说这种数据结构能在sqrt(N)的时间内维护树上的各种信息,十分的高效。当然,无聊的小Y对这种事情毫无兴趣,只是对把树分块这个操作感到十分好奇。他想,假如能把一棵树分成几块,使得每个块中的点数都相同该有多优美啊!小Y很想知道,能有几种分割方法使得一棵树变得优美。小Y每次会画出一棵树,但由于手速太快,有时候小Y画出来的树会异常地庞大,令小Y感到十分的苦恼。但是小Y实在是太想知道答案了,于是他找到了你,一个天才的程序员,来帮助他完成这件事。

    Input

    第一行一个正整数N,表示这棵树的结点总数,接下来N-1行,每行两个数字X,Y表示编号为X的结点与编号为Y的结点相连。结点编号的范围为1-N且编号两两不同。

    Output

    一行一个整数Ans,表示所求的方案数。

    Sample Input

    6
    1 2
    2 3
    2 4
    4 5
    5 6

    Sample Output

    3

    HINT

    100%的数据满足N<=1000000。

    Solution

    我竟然天真的以为$2e8$能跑过去直到我被最大的点卡到$10s$……

    感觉也说不上什么算法,就算他是乱搞吧。

    一开始洲哥给了一个$nsqrt{n}$的写法。下一段根号做法可以不看因为我感觉我写的可能比正解还难懂……

    我们先枚举当前要分的块大小$k$,再随便找一个根$DFS$一下,从下往上贪心的分,也就是够$k$个就分成一块。感性理解一下还是非常正确的……对于每个点$x$我们求出$(sum size[son[x]]\%k)+1$,如果存在某个点的这个值大于$k$的话显然就是不合法的。其中$size[son[x]]\%k$也就是$son[x]$这颗子树里面分完了剩下的点。这个为什么是对的我就不多说了……要真想不懂的话可以直接去看下面正解做法。

    其实仔细想想,确定了块大小$k$之后,那么每一块内的根的$size$肯定就是$k$的倍数。这个应该还是比较显然的,因为你是从下往上贪心来分的。那么我们直接开个桶记下$size$,对于每一个能被$n$整除的块大小$k$,统计有多少$size[x]$被$k$整除,如果与$n/k$相同则合法。复杂度应该是$O(n+sqrt{n}logn)$

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #define N (1000009)
     5 using namespace std;
     6 
     7 struct Edge{int to,next;}edge[N<<1];
     8 int n,ans,size[N],u,v,Keg[N];
     9 int head[N],num_edge;
    10 
    11 inline int read()
    12 {
    13     int x=0; char c=getchar();
    14     while (c<'0' || c>'9') c=getchar();
    15     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
    16     return x;
    17 }
    18 
    19 void add(int u,int v)
    20 {
    21     edge[++num_edge].to=v;
    22     edge[num_edge].next=head[u];
    23     head[u]=num_edge;
    24 }
    25 
    26 void DFS(int x,int fa)
    27 {
    28     size[x]=1;
    29     for (int i=head[x]; i; i=edge[i].next)
    30         if (edge[i].to!=fa)
    31         {
    32             DFS(edge[i].to,x);
    33             size[x]+=size[edge[i].to];
    34         }
    35     Keg[size[x]]++;
    36 }
    37 
    38 int main()
    39 {
    40     n=read();
    41     for (int i=1; i<=n-1; ++i)
    42     {
    43         u=read(); v=read();
    44         add(u,v); add(v,u);
    45     }
    46     DFS(1,0);
    47     for (int i=1; i<=n; ++i)
    48         if (n%i==0)
    49         {
    50             int sum=0;
    51             for (int j=1; i*j<=n; ++j)
    52                 sum+=Keg[i*j];
    53             ans+=(sum==n/i);
    54         }
    55     printf("%d
    ",ans);
    56 }
  • 相关阅读:
    struts2简介
    项目整合SpringDataRedis
    SpringDataRedis入门Demo
    包管理-rpm
    文件查找与压缩
    N042第一周
    Shell
    Linux下终端字体颜色设置方法
    文本处理工具作业
    正则表达式
  • 原文地址:https://www.cnblogs.com/refun/p/10219614.html
Copyright © 2011-2022 走看看