列表

详情


NC54342. 星球大战

描述

Y星球是一个美丽富饶的星球,然而最近它收到了来自X星人的攻击。为了能够抵御X星人,Y星人正在努力修建碉堡。
Y星球一开始只有一座碉堡该碉堡标号为1,以后每次Y星人会修建一个碉堡,该碉堡的标号为已经存在的碉堡的最大标号+1,并修建一条由fa_x通向新建碉堡的长度为1的单向道路。
每个碉堡都会有一些命令需要向其他碉堡传达。由于道路是有方向的,所以显然这些命令的传递也是有方向的。X星人的攻击方式很特别,具体的讲,他们每次会攻击一个碉堡,使得所有可以传递该碉堡发出的命令的道路有的概率损坏。
为了更好的建设碉堡,Y星球球长每次会告诉你他新建了一座新的碉堡并且修建了由fa_x连向这座新碉堡的道路。或者询问当x碉堡被攻击时。你从碉堡x开始命令期望传达的最远距离。
因为Y星人恢复能力极强所以前面的攻击并不会影响后面的询问。

点击下载大样例

输入描述

第一行两个整数,T,Q分别表示测试点编号和操作或询问的数量。样例文件中的T为0。
以后Q行,每行两个整数opt,x。
如果opt=1表示新建一个节点,并由标号为x的碉堡向新建碉堡连接一条单向道路,保证x为已经存在的碉堡。
如果opt=2表示询问当X星人攻击x碉堡时,x碉堡发出的令命期望传递的最远距离。

输出描述

对于每个opt=2的询问,你需要回答一个实数。

如果你的答案与标准答案的绝对误差或相对误差不超过即被视为正确。形式化的讲,如果你的答案为x,标准答案为y。答案正确当且仅当

示例1

输入:

0 7 
1 1 
1 1
2 1
1 2 
1 3 
2 2 
2 1

输出:

0.7500000000
0.5000000000
1.1875000000

说明:

第一次询问时碉堡网络的形态如下图。



所有可能被成功损坏的道路情况及其答案分别为:
{\emptyset}:1
{1}:1
{2}:1
{1,2}:0
所有情况概率均为\frac{1}{4},所以期望传递长度为\frac{1+1+1+0}{4}=0.75

第二和第三次询问时碉堡形态如下图。



当攻击2号点时所有可能被成功损坏的道路情况及其答案分别为:
{\emptyset}:1
{3}:0
每种情况概率为\frac{1}{2},所以期望最长传递长度为\frac{1}{2}=0.5
当攻击1号点时所有可能被成功损坏的道路情况及其答案分别为:
{\emptyset}:2
{1}:2
{3}:2
{2}:2
{4}:2
{1,2}:0
{1,3}:2
{1,4}:1
{2,3}:1
{2,4}:2
{3,4}:1
{1,2,3}:0
{1,2,4}:0
{1,3,4}:1
{2,3,4}:1
{1,2,3,4}:0
每种情况的概率均为\frac{1}{2^4},所以期望传递的最长长度为\frac{2\times 7+1\times5}{16}=1.1875

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 428ms, 内存消耗: 282280K, 提交时间: 2023-01-18 18:57:55

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define ld long double
#define FILE(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout)
using namespace std;
const int N=5e5+5,H=71;
double dp[N][H];
int tot=1,fa[N];
inline int read()
{
	int x=0,f=1;
	char c=getchar();
	while(!isdigit(c))
	{
		f=c^'-'?1:-1;
		c=getchar();
	}
	while(isdigit(c))
	{
		x=(x<<1)+(x<<3)+(c^'0');
		c=getchar();
	}
	return x*f;
}
inline void change(int p)
{
	double last=dp[p][0];
	dp[p][0]/=2;
	for(int now,h=1;h<H;++h)
	{
		if(!(now=fa[p]))
			break;
		double res=dp[now][h]/(0.5+0.5*last)*(0.5+0.5*dp[p][h-1]);
		p=now;
		last=dp[now][h];
		dp[now][h]=res;
	}
}
inline double query(int x)
{
	double res=0;
	for(int i=1;i<H;++i)
		res+=i*(dp[x][i]-dp[x][i-1]);
	return res;
}
signed main()
{
	int T=read(),q=read();
	fill(dp[1],dp[1]+H,1);
	while(q--)
	{
		int opt=read(),x=read();
		if(opt==1)
		{
			fa[++tot]=x;
			for(int i=0;i<H;++i)
				dp[tot][i]=1;
			change(x);
		}
		else
			printf("%.7lf\n",query(x));
	}
	return 0;
}

C++14(g++5.4) 解法, 执行用时: 508ms, 内存消耗: 162656K, 提交时间: 2019-12-12 14:51:36

#include<bits/stdc++.h>
using namespace std;
const int maxn = 500010;
const int lim = 40;
double dp[maxn][lim];   //i号点dep<=j层的概率
int fa[maxn], sz;

void extend(int x){
    sz++;   fa[sz]=x;
    for (int i=0;i<lim;++i){
        dp[sz][i]=1;
    }
    return ;
}

void update(int x){
    int dep=1, u;
    double pre1, pre2;
    pre1=dp[x][0];
    dp[x][0]*=0.5;
    while(dep<lim && fa[x]!=0){
        u=fa[x];
        pre2=dp[u][dep];
        dp[u][dep]/=(0.5+0.5*pre1);
        dp[u][dep]*=(0.5+0.5*dp[x][dep-1]);
        x=fa[x];    pre1=pre2;
        dep++;
    }
    return ;
}

int main(){
    int T;
    scanf("%*d%d",&T);
    sz=0;
    extend(0);
    int op, x;
    while(T--){
        scanf("%d%d",&op,&x);
        if (op==1){
            extend(x);
            update(fa[sz]);
        }else{
            double ans=0;
            for (int i=1;i<lim;++i){
                ans+=(dp[x][i]-dp[x][i-1])*i;
            }
            printf("%.7f\n",ans);
        }
    }

    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 573ms, 内存消耗: 276304K, 提交时间: 2019-12-09 18:15:24

#include<bits/stdc++.h>
using namespace std;

const int N=500010,sz=70;
int T,q,tot,fa[N];
double f[N][sz];

int main(){
	scanf("%d %d",&T,&q);tot=1;
	fill(f[1]+1,f[1]+sz,1);f[1][0]=0;
	int type,x;
	while(q--){
		scanf("%d %d",&type,&x);
		if(type==1){
			fa[++tot]=x;
			fill(f[tot]+1,f[tot]+sz,1);f[tot][0]=0;
			double now,last=1;
			for(int i=1,op=tot;x!=0 && i<sz;i++,x=fa[op=x]) now=(f[x][i]+1)/2,f[x][i]*=(f[op][i-1]+1)/2/last,last=now;
		}
		else{
			double ans=0;
			for(int i=1;i<sz;i++) ans+=1-f[x][i];
			printf("%.10lf\n",ans);
		}
	}
}

上一题