hdu5329(2015多校4)--Question for the Leader

题目链接:点击打开链接

题目大意:给出一个图,有n条点,n条边,如果要将这个图分为相同点数的k份,要求每一份内部都可以相互链接,那么一共会有几个k符合条件。

1、有一个定理,如果一颗树要分成k个节点一份的子树,那么有n/k个节点所对应子树的节点数是k的倍数。

根据上面这个定理,那么我们就可以计算一颗树能不能被分成n/k份,题目中给出了是一棵树+一条边,所以最终应该是一个环和以环上节点为根的子树,如果环上消除一条边,那么就变成了一颗树,就可以使用定理来判断了。

首先找出环上的节点,和以节点为根的子树大小。子树中节点数是不会变得可以直接使用。但是环中的节点数是会随着删除的边而变化的,所以要枚举删除的边,找到节点数是k的倍数的节点,如果是n/k个,那么证明k是可以的。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std ;
#pragma comment(linker,"/STACK:102400000,102400000") ;
#define maxn 100000+10
struct node{
    int v , next ;
}edge[maxn<<1] ;
int head[maxn] , h_cnt ;
int vis[maxn] ;
int a[maxn] , c[maxn] , n ;
int s[maxn] , m ;
int dp[maxn] ;
int cnt[maxn] , sum[maxn] ;
void add(int u,int v) {
    edge[h_cnt].v = v ;
    edge[h_cnt].next = head[u] ; head[u] = h_cnt++ ;
}
int f(int x) {
    return c[x] == x ? x : c[x] = f(c[x]) ;
}
int find1(int x,int y) {
    if( f(x) == f(y) ) return 1 ;
    c[ f(x) ] = f(y) ;
    return 0 ;
}
void dfs(int u) {
    dp[u] = 1 ;
    int i, v ;
    for(i = head[u] ; i != -1 ; i = edge[i].next) {
        v = edge[i].v ;
        if( vis[v] ) continue ;
        dfs(v) ;
        dp[u] += dp[v] ;
    }
    return ;
}
int solve(int k) {
    int i , max1 , temp = 0 ;
    memset(cnt,0,sizeof(cnt)) ;
    for(i = 1 ; i <= n ; i++) {
        if( vis[i] ) continue ;
        if( dp[i]%k == 0 ) temp++ ;
    }
    sum[0] = 0 ;
    for(i = 1 ; i<= m ; i++) {
        sum[i] = (sum[i-1] + dp[ s[i] ])%k ;
        cnt[ sum[i] ]++ ;
    }
    max1 = cnt[ sum[m] ] + temp ;
    for(i = 1 ; i < m ; i++) {
        cnt[ sum[i] ]-- ;
        cnt[ (sum[m]+sum[i])%k ]++ ;
        max1 = max(max1,cnt[ (sum[m]+sum[i])%k ]+temp) ;
    }
    if( max1 == n/k ) return 1 ;
    return 0 ;
}
int main() {
    int i , j , x , k ,ans ;
    //freopen("1003.in","r",stdin) ;
    //freopen("1111.out","w",stdout) ;
    while( scanf("%d", &n) != EOF ) {
        memset(head,-1,sizeof(head)) ;
        h_cnt = 0 ;
        memset(vis,0,sizeof(vis)) ;
        for(i = 1 ; i <= n ; i++) {
            scanf("%d", &a[i]) ;
            add(a[i],i) ;
            c[i] = i ;
        }
        for(i = 1 ; i <= n ; i++) {
            if( find1(i,a[i]) )
                break ;
        }
        m = 0 ;
        s[ ++m ] = i ;
        vis[i] = 1 ;
        x = a[i] ;
        while( x != s[1] ) {
            s[++m] = x ;
            vis[x] = 1 ;
            x = a[x] ;
        }
        for(i = 1 ; i <= m ; i++)
            dfs(s[i]) ;
        ans = 0 ;
        for(k = 1 ; k <= n ; k++) {
            if( n%k ) continue ;
            ans += solve(k) ;
        }
        printf("%d\n", ans) ;
    }
    return 0 ;
}

/*
12
7 9 12 2 3 4 8 6 10 5 8 1
*/

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-06 09:42:20

hdu5329(2015多校4)--Question for the Leader的相关文章

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&#39;s problem(manacher+二分/枚举)

HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分相同,第一部分与第二部分对称. 现在给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法,求出以第i个点为中心的回文串长度,记录到数组p中 要满足题目所要求的内容,需要使得两个相邻的回文串,共享中间的一部分,也就是说,左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也是一样. 因为我们已经记录下来以

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&amp;#39;s problem(manacher+二分/枚举)

pid=5371">HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分同样,第一部分与第二部分对称. 如今给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法.求出以第i个点为中心的回文串长度.记录到数组p中 要满足题目所要求的内容.须要使得两个相邻的回文串,共享中间的一部分,也就是说.左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也

hdu 5288||2015多校联合第一场1001题

http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a array A of size n ,defined a function f(l,r) represent the number of i (l<=i<=r) , that there's no j(l<=j<=r,j<>i) satisfy ai mod aj=0,now OO want to know ∑i

hdu5289||2015多校联合第一场1002贪心+RMQ

http://acm.hdu.edu.cn/showproblem.php?pid=5289 Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to

hdu5348(2015多校5)--MZL&#39;s endless loop(搜索)

题目链接:点击打开链接 题目大意:给出n个点,m条无向边,现在要求将无向边变为有向边,要保证每个点的出度和入度的差不超过1 直接进行搜索,对每个点进行出度和入度的判断,如果出度大,就先进行反向的搜索(每搜索一条边u,v就认为这是一条v到u的有向边),反之,进行正向搜索(每搜到一条边u,v认为这是一条u到v的有向边),一直搜索到找不到边能继续为止. 注意: 1.已经使用过的边为了防止再次被遍历,可以修改head,head[u] = edge[i].next 2.注意自环,因为搜索是判断能不能继续向

hdu5379||2015多校联合第7场1011 树形统计

http://acm.hdu.edu.cn/showproblem.php? pid=5379 Problem Description Little sun is an artist. Today he is playing mahjong alone. He suddenly feels that the tree in the yard doesn't look good. So he wants to decorate the tree.(The tree has n vertexs, i

hdu5351(2015多校5)--MZL&#39;s Border(打表,,找规律)

题目链接:点击打开链接 题目大意:给出b1 = 'b' , b2 = 'a' , bi = b(i-1)b(i-2),将i-1和i-2链接起来,记录一个串的s[1-i] 和s[n-i+1-n]相同的话 Border,当i为最长是为LBorder,现在给让求在bn这个串上的前m个字符组成的子串的LBorder 通过计算可以发现,b字符串的前缀都是相同的,所以只要求出m的LBorder就行,和n是无关的,打表找出规律,找出对应不同的m,LBorder的值,因为存在大数,用java写 dp[i]第i层

hdu5353||2015多校联合第六场1001 贪心

http://acm.hdu.edu.cn/showproblem.php?pid=5353 Problem Description There are n soda sitting around a round table. soda are numbered from 1 to n and i-th soda is adjacent to (i+1)-th soda, 1-st soda is adjacent to n-th soda. Each soda has some candies

2015 多校 #5 1005 MZL&#39;s chemistry

MZL's chemistry Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1306    Accepted Submission(s): 601 Problem Description MZL define F(X) as the first ionization energy of the chemical element X N