ADPC2-G 希望

Posted Jozky86

tags:

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

希望

题意:

有A,B两棵树,对于一个1到n的全排列a[i],让树A中的点i和树B的节点a[i]连一条边,希望指数:两棵树和新加入的边构成的图中,环长为m的环的个数。数组a[]可以任意交换位置,且任意,随机,不限次数的交换。计算出期望情况下,两棵树的希望指数
n≤300,3≤m≤7

题解:

期望=概率 * 对应的权值
在本题中概率肯定是 1 n ! \\frac{1}{n!} n!1,因此需要求所有情况下环长为m的环的个数
我们开始找环的分布情况,一定是左侧的点和右侧的点通过之间加的点形成环,如图,图中环长为6

且所有环用到中间新建边只能为两条边,可能会疑惑,为什么?像图中情况,用到的新建边的数量为4,不是2,但是图中环的长度为8(这已经是新建边4所对应的环最小长度),而题目保证所求环长<=7,刚好不行。也就是其实题目是隐含着新建边最多用两条,不可能更多

我们确定了中间边只能用2,那就好说了,比如让你求环为x的数量,x先减2,y=x-2,然后就是两个树一共构成长度为y,因此我们预先处理出两个子树分别能组成长度为len的边的数量,用桶来存。比如:tong1[i]:表示在树A中长度为i的边的数量。那么答案就: t o n g 1 [ i ] ∗ t o n g 2 [ m − i − 2 ] ∗ 2.0 ∗ ( ( n − 2 ) ) tong1[i]*tong2[m-i-2]*2.0*((n-2)) tong1[i]tong2[mi2]2.0((n2))
i是树A需要提供的边,m-i-2是树B需要提供的边,乘2.0是因为边可以交叉和不交叉来,正好两种,而最后(n-2)!是什么?我们之前说过最多用新增边为2,那么说明左右各有两个点要被占用(因为一个边有两个点),而其他的点可以任意排列,剩下的点就是(n-2)个,任意排列就是阶乘
再讲一些细节:
比如树上所有路径长度,可以用floyd来求,因为答案要乘(n-2)!,而最终答案还要除以n!,所以直接除以n*(n-1)即可

代码:

#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
    x= 0;
    char c= getchar();
    bool flag= 0;
    while (c < '0' || c > '9')
        flag|= (c == '-'), c= getchar();
    while (c >= '0' && c <= '9')
        x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
    if (flag)
        x= -x;
    read(Ar...);
}
template <typename T> inline void write(T x)
{
    if (x < 0) {
        x= ~(x - 1);
        putchar('-');
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
    startTime = clock ();
    freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
    endTime= clock();
    printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn=400;
vector<int>a[maxn],b[maxn],g[maxn];
int L[maxn];
int x[maxn][maxn];
int y[maxn][maxn];
int tong1[maxn],tong2[maxn];
int main()
{
    //rd_test();
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			x[i][j]=1e9;
			y[i][j]=1e9;
		}
	}
	for(int i=1;i<n;i++){
		int u,v;
		read(u,v);
		x[u][v]=x[v][u]=1;
	}
	for(int i=1;i<n;i++){
		int u,v;
		read(u,v);
		y[u][v]=y[v][u]=1;
		
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				x[i][j]=min(x[i][j],x[i][k]+x[k][j]);
				y[i][j]=min(y[i][j],y[i][k]+y[k][j]);
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			if(i==j)continue;
			if(x[i][j]==1e9)continue;
			if(y[i][j]==1e9)continue;
			tong1[x[i][j]]++;
			tong2[y[i][j]]++;
		}
	}
	double ans=0;
	for(int i=1;i<=m-3;i++){
		ans=ans+1.0*tong1[i]*tong2[m-i-2]*2.0/(1.0*n*(n-1));
	}
	
	printf("%.4lf\\n",ans);
	//Time_test();
}




以上是关于ADPC2-G 希望的主要内容,如果未能解决你的问题,请参考以下文章

Sphinx、reStructuredText 显示/隐藏代码片段

QT 实用代码片段

如何创建片段以重复变量编号中的代码行

我应该如何使用 Outlook 发送代码片段?

如何在android中将json数据加载到片段中

用于从 cloudkit 检索单列的代码模式/片段