做法一:反向建树,反正每个徒弟只有一个师傅,路径是单一的,就从得道者这个位置一直找到0这个祖师爷(看到这没事了,数据辣么大必超时,但对于菜鸡的我来说,写法简单又能偷个十几分也挺满意的了)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5;
vector<int> v[N];
double sum=0;
int st[N];
int num=0;
int n,k,x;
double a,b;
void dfs(int u)
{
if(u==0)
{
sum+=a*pow(1-b/100,num)*x;
return ;
}
for(auto j:v[u])
{
num++;
dfs(j);
num--;
}
}
signed main()
{
cin>>n>>a>>b;
for(int i=0;i<n;i++)
{
cin>>k;
if(k==0)
{
cin>>x;
memset(st,0,sizeof st);
num=0;
dfs(i);
}
else
{
while(k--)
{
cin>>x;
v[x].push_back(i);
}
}
}
cout<<(int)sum<<endl;
}
做法二:思路差不多,直接用并查集(但有一个样例没过)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n;
double a,b;
double sum=0;
int p[N];
int x,k;//得道者增加的倍数
int num=0;//记录传了几代
void find(int u)
{
while(p[u]!=u)
{
u=p[u];
num++;
}
sum+=a*pow(1-b/100,num)*x;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>a>>b;
for(int i=0;i<n;i++) p[i]=i;
for(int i=0;i<n;i++)
{
cin>>k;
if(k==0)
{
cin>>x;
num=0;
find(i);
}
else
{
while(k--)
{
cin>>x;
p[x]=i;
}
}
}
cout<<(int)sum<<endl;
}
做法三:(ak做法,别人的)
#include <bits/stdc++.h>
using namespace std;
int n,k,vis[100010],x;//二维动态数组
double z,r,sum;
vector<vector<int>> v;
//传入 第index位师父,和功力值
void dfs(int index,double power) {
if(vis[index]) { //这是得道者
sum=sum+power*v[index][0];//这里为什么是 v[index][0]???
//得道者就不会在收徒弟的样子!!! 见图
return ;
}
for(int i=0; i<v[index].size(); i++) {
dfs(v[index][i],power*(1-r/100));
}
}
int main() {
cin>>n>>z>>r;
v.resize(n);
for(int i=0; i<n; i++) {
cin>>k;
if(!k) { //k==0,这是一个得道者
cin>>x;
vis[i]=1;//置为1
v[i].push_back(x);//第i位师父的徒弟是x
}
while(k--) {
cin>>x;
v[i].push_back(x);
}
}
dfs(0,z);
cout<<(int)sum<<endl;
return 0;
}