CodeForces - 697D - Puzzles DFS

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: justify; font: 10.5px "Trebuchet MS"; color: #000000 }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: justify; text-indent: 21.0px; font: 10.5px "PingFang SC"; color: #000000 }
p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: justify; text-indent: 21.0px; font: 10.5px "Trebuchet MS"; color: #000000 }
span.s1 { }
span.s2 { font: 10.5px "Trebuchet MS" }
span.s3 { font: 10.5px "PingFang SC" }
span.Apple-tab-span { white-space: pre }

传送门:D - Puzzles

题意:在一个图中,从1开始dfs,求每一个点到达的期望;

思路:(下面是队长写的)

首先求的是到每一个点的步数的期望.

记fa( u ) = v, son( v )表示v的儿子的集合,

z是son(v)中的点,其中 z != u ,  sum[z] 为 z 的子树的大小, p( z )表示z比u先访问到的概率;

那么可以发现对于u来说 ans[u] = ans[v] + 1 + x;

现在我要来算这个x, 如果 son(v).size == 1, 那么x为0;

否则能对u造成影响的就是son(v)中不是u的那些点,

以z为例, 如果z先于u访问到,那么到达u的步数就会加上sum[z], 那么 x += sum[z] * p(z);

可以发现这样一个规律对于son(v)任意一种排列a,都可以发现一种对应排列b,满足a和b中只有u和z的位置对换.而且u和v不可能同时被访问或者其中一个不被访问,那么可以得到p(z) = 0.5; 就是 x += sum[z] * 0.5;

那么x就可以算出来了: for(auto it : son[v]) x += sum[it] * 0.5;

时间复杂度O(n);

所以下面的ac代码中,dfs1()就是求每一个点的sum值,通过类似前缀和的思想;

          get1()就是求ans;

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;

const int maxn = 100007;

int n,sum[maxn];
vector<int>mp[maxn];
double ans[maxn];
void init(){
    for(int i=1;i<=n;i++)
        mp[i].clear();
    memset(ans,0,sizeof(ans));
    memset(sum,0,sizeof(sum));
}
void dfs1(int d)
{
    sum[d] = 1;
    for(int  t=0; t < mp[d].size(); t++)
    {
        int to = mp[d][t];
        dfs1(to);
        sum[d] += sum[to];
    }
}
void get1(int d)
{
    for(int t=0; t<mp[d].size(); t++)
    {
        int to = mp[d][t];
        ans[to] = ans[d] + 1 + (sum[d]-sum[to]-1) * 0.5;
        get1(to);
    }
}
int main(){
  //  freopen("in","r",stdin);
    while(~scanf("%d", &n))
    {
        init();
        for(int i=2; i<=n; i++)
        {
            int x;
            scanf("%d",&x);
            mp[x].push_back(i);
        }
        dfs1(1);
        ans[1] = 1.0;
        get1(1);
        for(int i=1; i<=n; i++)
        {
            printf("%.1f%c", ans[i], i==n?‘\n‘:‘ ‘);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ckxkexing/p/8584025.html

时间: 2024-10-04 16:58:39

CodeForces - 697D - Puzzles DFS的相关文章

CodeForces 337A Puzzles

Puzzles Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on CodeForces. Original ID: 337A64-bit integer IO format: %I64d      Java class name: (Any) The end of the school year is near and Ms. Manana, the teacher, will soon have t

codeforces 377A. Puzzles 水题

A. Puzzles Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/337/A Description The end of the school year is near and Ms. Manana, the teacher, will soon have to say goodbye to a yet another class. She decided to p

【数学相关、规律】Codeforces 696B Puzzles

题目链接: http://codeforces.com/problemset/problem/696/B 题目大意: 给一棵树,从根节点开始递归,time=1,每次递归等概率随机访问这个节点的子节点,走过不会再走,每访问到一个新节点time+1,求访问每个节点的时间的期望. 题目思路: [数学规律] 这题其实是一道概率DP的题目,但是找规律后发现答案和当前结点的子树大小有关. ans[v]=ans[u]+1+0.5*(child[u]-child[v]-1),child为当前节点的子树大小. 1

Codeforces 767C. Garland (dfs)

题目链接: http://codeforces.com/problemset/problem/767/C 题意: 一棵树,每个节点有一个权值t,把它分成三部分,每部分要求权值和相等. 思路: 由于子树的子树里再出现等于sum/3的情况,那么dp[u]=0,就可以很好的避免计算情况了 dfs  第一找出来一个sum/3,然后子树结果清零,然后再dfs一次,直接忽视掉前一个sum/3,找出第二个sum/3,如果能找出来就输出,不能就-1. 还有一种笨写法.(傻逼的我调了半辈子) 代码: 代码一: #

Codeforces 104C Cthulhu dfs暴力 || 双连通缩点

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 问图中是否存在 有且仅有一个简单环和一些树,且这些树的root都在这个简单环上. 瞎写了个点双..== #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <queue> #include <vector> #include <set> us

CodeForces 731C Socks (DFS或并查集)

题意:有n只袜子,k种颜色,在m天中,问最少修改几只袜子的颜色,可以使每天穿的袜子左右两只都同颜色. 析:很明显,每个连通块都必须是同一种颜色,然后再统计最多颜色的就好了,即可以用并查集也可以用DFS. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include

Codeforces 723d [暴力dfs]

/* 不要低头,不要放弃,不要气馁,不要慌张. 题意: 给n,m和k,n和m为所给矩阵的高和宽.k是要求最多剩下的湖的数量. 在所给的矩阵中,*代表陆地,.代表水. 湖的定义是一片连续的水(上下左右四个方向),并且水不含边界. 水含边界的情况被成为海. 问最少填多少湖的面积,使得湖的数量减少到k... 思路: 水dfs,记录有多少湖,并且记录每个湖的面积,然后排下序贪心就好. 坑: 做题一定别急一定别急一定别急一定知道自己写的是什么!!!! */ #include<bits/stdc++.h>

Codeforces 27B - Tournament (dfs)

题意 有n支队伍,他们之间所有队伍都要打一遍,其中有一对的结果没有给出,求这场比赛的结果. 思路 显然我们能从给出的这些对求出有哪两个队伍没给出. 然后就是要判断这两队的胜负情况,dfs判断一下有向图中其中一个是不是能到达另一个就可以了. 代码 #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #inc

CodeForces 696B Puzzles

思维,简单树$dp$. 首先计算出每一个子树包含多少个节点,记为$f[i]$.然后就可以从$root$开始推出所有节点的期望了. 现在已知$fa$节点的答案为$ans[fa]$,假设要计算$fa$的一个儿子$v$的期望,那么$ans[v]=ans[fa]+1.0+(f[fa]-f[v]-1)/2.0$. 我画了一下样例,然后猜测了一下发现是对的...... #pragma comment(linker, "/STACK:1024000000,1024000000") #include&