您的位置:首页 > 其它

[BZOJ]2337: [HNOI2011]XOR和路径 期望+高斯消元

2017-10-18 08:31 459 查看
Description



题解:

好题啊!以前都不知道高斯消元还能这样用!看到xor,我们可以想到拆位,这样算出每位为1的期望然后乘上一个权值就是答案了。假设我们现在处理到第j位,为了方便,我们把每条边的权值看做它的第j位,令f[i]表示i到n这一位为1的期望,我们可以分这条边的权值为0或1的情况讨论,很容易推出式子,我就懒得写了,然后显然f[n]=0(因为走到n就停下)。为什么这里不定义状态为从1走到i的期望呢?因为不好推,没有一个确定的f。又因为这个图不是DAG,所以f不能直接推出来,而且f之间会互相影响,所以选择用高斯消元解方程求出f。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const long double eps=1e-8;
const int Maxn=110;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
int n,m,degree[Maxn];
struct Edge{int y,next,d;}e[20010];
int last[Maxn],len=0;
void ins(int x,int y,int d)
{
int t=++len;
e[t].y=y;e[t].d=d;e[t].next=last[x];last[x]=t;
}
long double a[Maxn][Maxn];
void gauss()
{
for(int i=1;i<n;i++)
{
if(abs(a[i][i])<=eps)
{
for(int j=i+1;j<n;j++)
if(abs(a[j][i])>eps)
{
for(int k=i;k<=n+1;k++)swap(a[j][k],a[i][k]);
break;
}
}
for(int j=i+1;j<n;j++)
if(abs(a[j][i])>eps)
{
long double t=a[j][i]/a[i][i];
for(int k=i;k<=n+1;k++)a[j][k]-=t*a[i][k];
}
}
for(int i=n-1;i;i--)
{
for(int j=i+1;j<=n;j++)
a[i][n+1]-=a[i][j]*a[j][n+1];
a[i][n+1]/=a[i][i];
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),d=read();
degree[y]++,ins(x,y,d);
if(x!=y)degree[x]++,ins(y,x,d);
}
long double ans=0.0;
for(int j=0;j<31;j++)
{
for(int p=1;p<=100;p++)
for(int q=1;q<=101;q++)
a[p][q]=0.0;
for(int x=1;x<n;x++)
{
a[x][x]=(long double)(degree[x]);
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y,d=((e[i].d>>j)&1);
if(d)a[x][y]+=1.0,a[x][n+1]+=1.0;
else a[x][y]-=1.0;
}
}
gauss();ans+=a[1][n+1]*(long double)(1<<j);
}
printf("%.3Lf",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: