【BZOJ 2337】 2337: [HNOI2011]XOR和路径(概率DP、高斯消元)

2337: [HNOI2011]XOR和路径

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1170  Solved: 683

Description

【BZOJ 2337】 2337: [HNOI2011]XOR和路径(概率DP、高斯消元)

Input

Output

Sample Input

Sample Output

HINT

Source

【分析】

  这题终于自己打出来了高斯消元。没有对比代码了。。。

  很心酸啊。。调试的时候是完全没有方向的,高斯消元还要自己一步步列式子然后消元解。。【为什么错都不知道有时候

  这题显然是不能直接记录异或和然后DP的。

  显然是要拆位的。

  拆位之后f[i][0]表示从i走,走到终点,这一位异或和为0的概率。

  f[i][0]=f[j][0]*p (i->j 这一位边权为0)+f[j][1]*p (i->j 这一位边权为1)

  反之不写了

  f[n][0]=1 f[n][1]=0

  就是(2*n)^2规模的高斯消元。

  然后用f[1][1]乘这一位的贡献加进答案里面就好。

  一开始被卡精,eps太小,后来数组爆一位!!醉了!!

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define Maxn 110
#define Maxm 10010
const double eps=1e-; struct node
{
int x,y,c,next;
}t[Maxm*];
int first[Maxn],len;
double d[Maxn];
void ins(int x,int y,int c)
{
d[x]+=1.0;
t[++len].x=x;t[len].y=y;t[len].c=c;
t[len].next=first[x];first[x]=len;
} bool dcmp(double x) {return fabs(x)>eps;} double a[*Maxn][*Maxn],f[*Maxn];
void gauss(int n)
{
for(int i=;i<n;i++)
{
// if(a[i][i]==0) continue;
int t=i;
for(int j=i+;j<=n;j++) if(fabs(a[j][i])>fabs(a[t][i])) t=j;
if(t!=i)
{
for(int j=;j<=n;j++) swap(a[i][j],a[t][j]);
}
for(int j=i+;j<=n;j++)
{
double t=a[j][i]/a[i][i];
if(dcmp(a[j][i]))
{
for(int k=;k<=n;k++) a[j][k]-=a[i][k]*t;
}
}
}
for(int i=n-;i>=;i--)
{
for(int j=i+;j<n;j++) a[i][n]+=f[j]*a[i][j];
f[i]=-a[i][n]/a[i][i];
}
} int main()
{
int n,m,mx=;
scanf("%d%d",&n,&m);
len=;memset(first,,sizeof(first));
for(int i=;i<=n;i++) d[i]=;
for(int i=;i<=m;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
mx=max(mx,c);
ins(x,y,c);
if(x!=y) ins(y,x,c);
}
int l=;while((<<l)<=mx) l++;
double ans=;
for(int i=;i<=l;i++)
{
for(int j=;j<=n+n;j++) for(int k=;k<=n+n;k++) a[j][k]=;
for(int j=;j<n;j++)
{
a[j][j]=1.0;a[j+n][j+n]=1.0;
for(int k=first[j];k;k=t[k].next)
{
int y=t[k].y;
if(t[k].c&(<<i)) a[j][y+n]-=1.0/d[j],a[j+n][y]-=1.0/d[j];
else a[j][y]-=1.0/d[j],a[j+n][y+n]-=1.0/d[j];
}
a[j][(n<<)+]=a[j+n][(n<<)+]=;
}
a[n][n]=1.0;a[n+n][n+n]=1.0;
a[n][(n<<)+]=-1.0;a[n<<][(n<<)+]=;
gauss((n<<)+);
// printf("%.10lf\n",f[n+1]);
ans+=1.0*(<<i)*f[n+];
}
printf("%.3lf\n",ans);
return ;
}

【怎么说回家前A掉这题还是很兴奋的

【也说明我能自己打出概率的高斯消元了耶!

2017-04-22 16:06:09

上一篇:BZOJ 2337 [HNOI2011]XOR和路径 ——期望DP


下一篇:使用CMD 命令创建指定大小的文件