题解:CF235D Graph Game
Danslapiscine · · 题解
好题啊。基本把期望线性性玩明白了。
利用期望线性性,首先可以拆贡献。要计算“某个点在点分治过程中被遍历的期望次数”。所有点分别计算后求和就是答案。
然后可以手玩这个分治过程,假设要计算的点为
要解决如上问题,依然可以拆贡献。要计算“
以下图情况(
首先我们构造一个“操作序列”,是一个
具体来说,在第
消完后即得到实际操作的概率。
欸?好像有道题也是这么个证法。
回到图上,
然后其他情况比这个简单,也是这么推的。
然后这道题就做完了。
时间复杂度
#include <bits/stdc++.h>
using namespace std;
int n;
vector<int> vec[3002];
int du[3002];
queue<int> q;
bool incir[3002];
int cirtot;
void forcir(){
for(int i=1;i<=n;i++) incir[i] = 1;
cirtot = n;
for(int i=1;i<=n;i++) if(du[i] == 1) q.push(i);
while(!q.empty()){
int u = q.front();
q.pop();
incir[u] = 0;
cirtot--;
for(int i=0;i<vec[u].size();i++){
int v = vec[u][i];
du[v]--;
if(du[v] == 1){
q.push(v);
}
}
}
}
int dep[3002], a[3002];
bool vis[3002];
double solve(int pos,int fa){
//cout << pos <<endl;
double ret = 0;
if(!incir[pos]) dep[pos] = dep[fa] + 1, a[pos] = a[fa];
else dep[pos] = dep[fa], a[pos] = a[fa] + 1;
double S = dep[pos]+min(a[pos],2);
if(a[pos] > 2 && cirtot - a[pos] > 0) ret += 1.0 / (S + a[pos]-2) + 1.0 / (S + cirtot-a[pos]) - 1.0 / (S + cirtot-2);
else ret += 1.0 / S;
for(int i=0;i<vec[pos].size();i++){
int v = vec[pos][i];
if(vis[v]) continue;
vis[v] = 1, ret += solve(v,pos);
}
return ret;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int u, v;
scanf("%d%d",&u,&v);
u++, v++;
vec[u].push_back(v);
vec[v].push_back(u);
du[u]++, du[v]++;
}
forcir();
//for(int i=1;i<=n;i++) cout << incir[i] << ' ';
//cout << endl;
double Ans = 0;
for(int i=1;i<=n;i++){
//cout << i << endl;
for(int j=1;j<=n;j++) vis[j] = 0;
vis[i] = 1, Ans += solve(i,0);
}
printf("%.10f",Ans);
return 0;
}