HDU - 5329 Question for the Leader 基环树 + dp

HDU - 5329

首先肯定要把基环扣出来, 然后我们枚举每个块的大小k, k肯定是n的因子。

把基环上的点作为树根先把它们的子树都分成k份, 如果无法分肯定不行, 

如果都可以分, 那么每个基环上的点可能还有一些没有达到k个, 我们需要

把相邻的基环组合一下恰好变成k个, 这个可以尺取 + dp 扫过去check, 

特别注意0是肯定要作为分界点的。。 这个对拍的时候才发现, debug了好久。

然后取解决基环上的子树的时候不能dfs, 会T, 要先排出拓扑序再for过去。

 

其实这个题有个结论就是, 一棵树能分成 x 份, 当且仅当子树大小为n / x的倍数的恰好有 x 个。
有这个结论的话for过去枚举断的边可能会比较方便, 常数也比较小。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

int n;
int vis[N], idx;
int fa[N];
int cir[N], cirCnt;
int ok[N];
int dp[N];
int val[N];
int sum[N];
int mnPos[N];
int id[N], tot;
int K;

vector<int> fac[N];
vector<PII> G[N];

void dfs(int u, int pid) {
    vis[u] = ++idx;
    for(auto &e : G[u]) {
        if(e.fi == pid) continue;
        if(!vis[e.se]) {
            fa[e.se] = u;
            dfs(e.se, e.fi);
        }
        else {
            int v = e.se;
            if(vis[u] < vis[v]) {
                cir[++cirCnt] = v;
                for(; v != u; v = fa[v]) {
                    cir[++cirCnt] = fa[v];
                }
            }
        }
    }
}


void go(int u, int fa) {
    ::fa[u] = fa;
    for(auto &e : G[u]) {
        int v = e.se;
        if(v == fa || !ok[v]) continue;
        go(v, u);
    }
    id[++tot] = u;
}

bool solve(int k) {
    K = k;
    int zero = 0;

    for(int i = 1; i <= n; i++) {
        dp[i] = 1;
    }

    for(int i = 1; i <= n; i++) {
        if(dp[id[i]] > K) return false;
        if(dp[id[i]] == K) dp[id[i]] = 0;
        dp[fa[id[i]]] += dp[id[i]];
    }

    for(int i = 1; i <= cirCnt; i++) {
        val[i] = val[i + cirCnt] = dp[cir[i]];
        zero += val[i] == 0;
    }

    if(zero == cirCnt) {
        return true;
    }

    for(int i = 1; i <= 2 * cirCnt; i++) {
        sum[i] = sum[i - 1] + val[i];
        mnPos[i] = 2 * cirCnt + 1;
    }

    for(int i = 1, j = 1; i <= 2 * cirCnt; i++) {
        if(val[i] == 0) {
            mnPos[i] = min(mnPos[i - 1], i - 1);
            j = i + 1;
            continue;
        }
        while(j < i && sum[i] - sum[j - 1] > K) j++;
        if(sum[i] - sum[j - 1] == K) {
            mnPos[i] = min(j - 1, mnPos[j - 1]);
            if(i - mnPos[i] >= cirCnt) return true;
        }
    }
    return false;
}

void init() {
    idx = 0;
    for(int i = 1; i <= n; i++) {
        G[i].clear();
        ok[i] = 1;
        vis[i] = 0;
    }
    cirCnt = 0;
    tot = 0;
}

int main() {
    for(int i = 2; i <= 100000; i++) {
        for(int j = 2 * i; j <= 100000; j += i) {
            fac[j].push_back(i);
        }
    }

    while(scanf("%d", &n) != EOF) {

        init();

        for(int i = 1; i <= n; i++) {
            int u;
            scanf("%d", &u);
            G[i].push_back(mk(i, u));
            G[u].push_back(mk(i, i));
        }

        if(n == 1) {
            puts("1");
            continue;
        }

        dfs(1, 0);

        for(int i = 1; i <= cirCnt; i++) {
            ok[cir[i]] = 0;
        }

        for(int i = 1; i <= cirCnt; i++) {
            go(cir[i], 0);
        }

        int ans = 2;

        for(int i = 0; i < SZ(fac[n]); i++) {
            if(solve(fac[n][i])) {
                ans++;
            }
        }

        printf("%d\n", ans);
    }
    return 0;
}

/*
*/

 

posted @ 2019-07-27 10:16  NotNight  阅读(147)  评论(0编辑  收藏  举报