luogu 3565 bzoj 3522 & bzoj 4543

Posted zjxxcn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu 3565 bzoj 3522 & bzoj 4543相关的知识,希望对你有一定的参考价值。

hotel解题报告

1 方法1

  • 我们可以用(down[i][j])表示在(i)的子树里面距离为(j)的节点的个数,(up[i][j])表示通过(i)的父亲走到的距离为(j)的点的个数。

    [down[i][j]=sum_{all\_son}down[son][j-1] ]

    [up[i][j]=up[fa][j-1]+down[fa][j-1]-down[i][j-2] ]

    对于每个(x),对于它的每个深度(i)我们可以对每个儿子(son)执行:

    [ans+=t*down[son][i-1] ]

    [t+=sum*down[son][i-1] ]

    [sum+=down[son][i-1] ]

    最后我们做:

    [ans+=t*up[x][i] ]

  • 时间复杂度(o(n^2))

  • #include <bits/stdc++.h>
    using namespace std;
    int const N = 5000 + 10;
    #define ll long long
    struct edge
    {
    	int to, nt;
    } e[N << 1];
    int h[N], cnt, n; 
    short up[N][N], down[N][N];
    ll ans;
    void add(int a, int b)
    {
    	e[++cnt].to = b;
    	e[cnt].nt = h[a];
    	h[a] = cnt;
    }
    void dfs(int x, int fa)
    {
    	down[x][0] = 1;
    	for (int i = h[x]; i; i = e[i].nt)
    	{
    		int v = e[i].to;
    		if (v == fa)
    			continue;
    		dfs(v, x);
    		for (int j = 0; j < n; j++)
    			down[x][j + 1] += down[v][j];
    	}
    }
    void dfs2(int x, int fa)
    {
    	up[x][0] = 1;
    	if (fa)
    		up[x][1] = 1;
    	for (int i = 2; i <= n; i++)
    	{
    		up[x][i] = up[fa][i - 1];
    		if (fa)
    			up[x][i] += down[fa][i - 1] - down[x][i - 2];
    	}
    	for (int i = h[x]; i; i = e[i].nt)
    	{
    		int v = e[i].to;
    		if (v == fa)
    			continue;
    		dfs2(v, x);
    	}
    }
    void dfs3(int x, int fa)
    {
    
    	for (int i = 1; i <= n; i++)
    	{
    		int sum = 0, t = 0;
    		for (int j = h[x]; j; j = e[j].nt)
    		{
    			int v = e[j].to;
    			if (v == fa)
    				continue;
    			ans += t * down[v][i - 1];
    			t += sum * down[v][i - 1];
    			sum += down[v][i - 1];
    		}
    		ans += t * up[x][i];
    	}
    	for (int i = h[x]; i; i = e[i].nt)
    	{
    		int v = e[i].to;
    		if (v == fa)
    			continue;
    		dfs3(v, x);
    	}
    }
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i < n; i++)
    	{
    		int x, y;
    		scanf("%d%d", &x, &y);
    		add(x, y);
    		add(y, x);
    	}
    	dfs(1, 0);
    	dfs2(1, 0);
    	dfs3(1, 0);
    	cout << ans << endl;
    	return 0;
    }
    

2 方法2

  • 我们可以减少内存消耗,不用定义二维数组,我们每次只要考虑对于(x)来说的3个子孙就可以,不用考虑(x)的父亲的关系。我们枚举任何一个点都可以作为根节点。

  • 这样的时间复杂度仍旧是(O(n^2)),但是空间复杂度可以优化到(O(n))

  • #include <bits/stdc++.h>
    using namespace std;
    int const N = 5000 + 10;
    #define ll long long
    struct edge
    {
    	int to, nt;
    } e[N << 1];
    int h[N], cnt, n, tot[N], tmp[N], dep[N], num[N];
    ll ans;
    void add(int a, int b)
    {
    	e[++cnt].to = b;
    	e[cnt].nt = h[a];
    	h[a] = cnt;
    }
    void dfs(int x, int fa, int d)
    {
    	dep[x] = d;
    	for (int i = h[x]; i; i = e[i].nt)
    	{
    		int v = e[i].to;
    		if (v == fa)
    			continue;
    		dfs(v, x, d + 1);
    		dep[x] = max(dep[x], dep[v]);
    	}
    }
    void dfs2(int x, int fa, int d)
    {
    	tmp[d]++;
    	for (int i = h[x]; i; i = e[i].nt)
    	{
    		int v = e[i].to;
    		if (v == fa)
    			continue;
    		dfs2(v, x, d + 1);
    	}
    }
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i < n; i++)
    	{
    		int x, y;
    		scanf("%d%d", &x, &y);
    		add(x, y);
    		add(y, x);
    	}
    	for (int i = 1; i <= n; i++)
    	{
    		dfs(i, 0, 0);
    		memset(tot, 0, sizeof(tot));
    		memset(num, 0, sizeof(num));
    		for (int j = h[i]; j; j = e[j].nt)
    		{
    			int v = e[j].to;
    			for (int k = 1; k <= dep[v]; k++)
    				tmp[k] = 0;
    			dfs2(v, i, 1);
    			for (int k = 1; k <= dep[v]; k++)
    			{
    				ans += num[k] * tmp[k];
    				num[k] += tot[k] * tmp[k];
    				tot[k] += tmp[k];
    			}
    		}
    	}
    	cout << ans << endl;
    	return 0;
    }
    

以上是关于luogu 3565 bzoj 3522 & bzoj 4543的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3522 [Poi2014]Hotel

bzoj3522 Hotel

BZOJ 1002 && Luogu 2144 [FJOI 2007] 轮状病毒

[bzoj3522] [Poi2014]Hotel

bzoj2987&luogu5171 Earthquake

bzoj 3522 [Poi2014]Hotel 树形dp