码迷,mamicode.com
首页 > 其他好文 > 详细

[HNOI2011]XOR和路径

时间:2018-02-01 23:15:54      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:problem   解决   line   org   不能   swap   printf   tac   post   

题面
一道期望大火题(表示看了zsy大佬和ycb大佬的题解才过去的orz)

递推期望,因为是异或和,按照正常方法会很难,于是考虑按位DP(套路吧)
设状态的时候需要注意
如果设f[x]表示从1号节点到达x号节点且异或和为1的概率
那么在转移的时候,因为到达n号节点的时候就已经停止,所以f[n]不能转移;而我们又必须求出f[n],因此必须先对除n以外的所有点进行计算,再推到n,这样会很麻烦
于是想到倒着推,设f[x]表示从x号节点到达n号节点且异或和为1的概率,答案为f1,虽然说也不能从f[n]转移,但因为要求解的不是f[n]所以让就变得可行了

通过边进行转移:
\[f[u]=\sum_{v}\frac{f[v]}{d[u]}*[(u,v)==0]+\sum_{v}\frac{1-f[v]}{d[u]}*[(u,v)==1]\]
意即该位权值为1的点通过0边和该位权值为0的点通过1边到达点u所得的该位权值都是1

由于每个f[u]都和另外的f[v]产生依赖关系,故无法直接递推求解
高斯消元大显身手啦!!!!!!

接下来奉上本蒟蒻丑陋的代码


#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
const int mod=1e9+7;
const int N=110;
const double eps=1e-10;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
il ll read(){
    RG ll data=0,w=1;RG char ch=getchar();
    while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar();
    if(ch==‘-‘)w=-1,ch=getchar();
    while(ch<=‘9‘&&ch>=‘0‘)data=data*10+ch-48,ch=getchar();
    return data*w;
}

int n,m,head[N],nxt[N*N*2],to[N*N*2],val[N*N*2],d[N],cnt;
il void add(int u,int v,int w){
    to[++cnt]=v;d[v]++;
    val[cnt]=w;
    nxt[cnt]=head[u];
    head[u]=cnt;
}

dd S[35][N][N],ans[35][N],sum;
il bool gauss(int a){
    //高斯消元部分
    for(RG int i=1;i<=n;i++){
        for(RG int j=i;j<=n;j++)
            if(abs(S[a][j][i])>eps){
                swap(S[a][j],S[a][i]);break;
            }
        if(abs(S[a][i][i])<=eps)return 0;
        for(RG int j=i+1;j<=n;j++){
            ans[a][j]-=ans[a][i]*S[a][j][i]/S[a][i][i];
            for(RG int k=n;k>=i;k--)
                S[a][j][k]-=S[a][i][k]*S[a][j][i]/S[a][i][i];
        }
    }

    for(RG int i=n;i;i--){
        for(RG int j=i+1;j<=n;j++)
            ans[a][i]-=S[a][i][j]*ans[a][j];
        ans[a][i]/=S[a][i][i];
    }
    
    return 1;
}

int main()
{
    n=read();m=read();
    for(RG int i=1,u,v,w,t;i<=m;i++){
        u=read();v=read();w=read();t=0;
        add(u,v,w);if(u!=v)add(v,u,w);
    }

    //这里是统计系数
    for(RG int u=1;u<n;u++){
        for(RG int i=0;i<=32;i++)S[i][u][u]+=1.0;
        for(RG int i=head[u];i;i=nxt[i]){
            RG int v=to[i],t=0;
            while(t<=32){
                S[t][u][v]+=((val[i]&1)?1:(-1))*1.0/(d[u]*1.0);
                ans[t][u]+=((val[i]&1)?1:0)*1.0/(d[u]*1.0);
                val[i]>>=1;t++;
            }
        }
    }for(RG int i=0;i<=32;i++)S[i][n][n]+=1.0;
    //这样可以保证最后f[n]==0消除f[n]的影响
    
    for(RG int i=0;i<=32;i++)gauss(i);
    
    for(RG ll i=0,x=1;i<=32;i++){sum+=ans[i][1]*x;x<<=1;}
    //按位统计答案
    
    printf("%.3lf\n",sum);
    return 0;
}

注:还有一道[HNOI2013]游走和此题思想类似,仍未解决。明天再战!!!

[HNOI2011]XOR和路径

标签:problem   解决   line   org   不能   swap   printf   tac   post   

原文地址:https://www.cnblogs.com/cjfdf/p/8401507.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!