• BZOJ5207 : [Jsoi2017]隧道


    若$min(n,m)<min(n+1,m-1)$,则考虑计算左边与右边不连通的概率,然后用$1$减去它得到答案。

    若$min(n,m)geq min(n+1,m-1)$,则考虑计算对偶图中上边与下边不连通的概率。

    同时当$n<m$时还可以旋转$90$°来交换$n$和$m$,使得$mleq 9$。

    那么问题转化为,给定$n imes m$的网格图,每个点颜色为$0,1,2$,每条边有存在的概率,求每个连通块不同时含有颜色$1$和$2$的概率。

    连通性状压DP,设$f[i][j][S]$表示考虑到了$(i,j)$,轮廓线状态为$S$的概率。

    其中$S$记录轮廓线上$m$个点所属连通块的最小表示,以及每个连通块的颜色。

    为了避免map的使用,可以考虑扩展出所有状态后再进行排序,将相同状态的DP值合并,减小常数。

    同时可以将$1$和$2$内部的边存在的概率设置为$1$,减小连通块的数量已达到优化状态数的效果。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=115,M=1000000,P=1000000007;
    int n,m,o,i,j,k,_id[N][N],_wr[N][N],_wd[N][N],id[N][N],wr[N][N],wd[N][N];
    struct E{
      ll x;int y,v;
      E(){}
      E(ll _x,int _y,int _v){x=_x,y=_y,v=_v;}
    }e[2][M];
    int cnt[2];
    inline bool cmp(const E&a,const E&b){
      if(a.x!=b.x)return a.x<b.x;
      return a.y<b.y;
    }
    inline void up(int&a,int b){a=a+b<P?a+b:a+b-P;}
    inline int po(int a,int b){int t=1;for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;return t;}
    inline int read(){
      int x;
      scanf("%d",&x);
      return 1LL*x*po(100,P-2)%P;
    }
    inline int read2(){
      int x=read();
      x=(P+1-x)%P;
      return x;
    }
    inline void fix(){
      int m=cnt[o],t=0,i,j,k;
      sort(e[o],e[o]+m,cmp);
      for(i=0;i<m;i=j){
        for(k=0,j=i;j<m&&e[o][i].x==e[o][j].x&&e[o][i].y==e[o][j].y;j++)up(k,e[o][j].v);
        if(k)e[o^1][t++]=E(e[o][i].x,e[o][i].y,k);
      }
      cnt[o^=1]=t;
    }
    inline ll get(ll x,int y){return x>>(y<<2)&15;}
    inline void cal(ll&A,int&B){
      static int v[N],f[N];
      int i,x,t=0,C=0;
      for(i=0;i<=m;i++)v[i]=-1;
      for(t=i=0;i<m;i++){
        x=get(A,i);
        if(v[x]==-1){
          C|=(B>>(x<<1)&3)<<(t<<1);
          v[x]=t++;
        }
        f[i]=v[x];
      }
      for(A=0,B=C,i=m-1;~i;i--)A=A<<4|f[i];
    }
    inline void up0(ll A,int B,int C,int x,int y){
      A^=(get(A,x)^m)<<(x<<2);
      B|=y<<(m<<1);
      cal(A,B);
      e[o^1][cnt[o^1]++]=E(A,B,C);
    }
    inline void upl(ll A,int B,int C,int x,int y){
      int t=get(A,x-1);
      if(y+(B>>(t<<1)&3)==3)return;
      A^=(get(A,x)^t)<<(x<<2);
      B|=y<<(t<<1);
      cal(A,B);
      e[o^1][cnt[o^1]++]=E(A,B,C);
    }
    inline void upu(ll A,int B,int C,int x,int y){
      int t=get(A,x);
      if(y+(B>>(t<<1)&3)==3)return;
      B|=y<<(t<<1);
      e[o^1][cnt[o^1]++]=E(A,B,C);
    }
    inline void upul(ll A,int B,int C,int x,int y){
      int t=get(A,x),z=get(A,x-1);
      if(y+(B>>(t<<1)&3)==3)return;
      B|=y<<(t<<1);
      if((B>>(z<<1)&3)+(B>>(t<<1)&3)==3)return;
      B|=(B>>(z<<1)&3)<<(t<<1);
      ll S=z^t;
      for(int i=0;i<m;i++)if(get(A,i)==z)A^=S<<(i<<2);
      cal(A,B);
      e[o^1][cnt[o^1]++]=E(A,B,C);
    }
    int solve(){
      if(n<m){
        for(i=1;i<=n;i++)for(j=1;j<m;j++)wd[j][i]=_wr[i][j];
        for(i=1;i<n;i++)for(j=1;j<=m;j++)wr[j][i]=_wd[i][j];
        for(i=1;i<=n;i++)for(j=1;j<=m;j++)id[j][i]=_id[i][j];
        swap(n,m);
      }else{
        for(i=1;i<=n;i++)for(j=1;j<=m;j++)wd[i][j]=_wd[i][j],wr[i][j]=_wr[i][j],id[i][j]=_id[i][j];
      }
      cnt[o=0]=1;
      e[0][0]=E(0,0,1);
      for(i=m-1;~i;i--)e[0][0].x=e[0][0].x<<4|i;
      for(i=1;i<=n;i++)for(j=1;j<=m;j++){
        int pl=j>1?wr[i][j-1]:0,npl=(P+1-pl)%P,
            pu=i>1?wd[i-1][j]:0,npu=(P+1-pu)%P,
            pul=1LL*pl*pu%P,p0=1LL*npl*npu%P,t=id[i][j];
        pl=1LL*pl*npu%P;
        pu=1LL*pu*npl%P;
        cnt[o^1]=0;
        for(k=0;k<cnt[o];k++){
          if(pl)upl(e[o][k].x,e[o][k].y,1LL*e[o][k].v*pl%P,j-1,t);
          if(pu)upu(e[o][k].x,e[o][k].y,1LL*e[o][k].v*pu%P,j-1,t);
          if(pul)upul(e[o][k].x,e[o][k].y,1LL*e[o][k].v*pul%P,j-1,t);
          if(p0)up0(e[o][k].x,e[o][k].y,1LL*e[o][k].v*p0%P,j-1,t);
        }
        o^=1;
        fix();
      }
      int ret=0;
      for(i=0;i<cnt[o];i++)up(ret,e[o][i].v);
      return ret;
    }
    int main(){
      int r,c,flag=0;
      scanf("%d%d",&r,&c);
      if(c<=1)return puts("1"),0;
      if(min(r,c)<min(r+1,c-1)){
        flag=1;
        for(i=1;i<=r;i++)for(j=1;j<c;j++)_wr[i][j]=read();
        for(i=1;i<r;i++)for(j=2;j<c;j++)_wd[i][j]=read();
        for(i=1;i<r;i++)_wd[i][1]=_wd[i][c]=1;
        for(i=1;i<=r;i++)_id[i][1]=1,_id[i][c]=2;
        n=r,m=c;
      }else{
        for(i=1;i<=r;i++)for(j=1;j<c;j++)_wd[i][j]=read2();
        for(i=1;i<r;i++)for(j=2;j<c;j++)_wr[i+1][j-1]=read2();
        for(i=1;i<c-1;i++)_wr[1][i]=_wr[r+1][i]=1;
        for(i=1;i<c;i++)_id[1][i]=1,_id[r+1][i]=2;
        n=r+1,m=c-1;
      }
      int ans=solve();
      if(flag)ans=(P+1-ans)%P;
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    struts2<s:property />标签
    struts2值栈分析
    Java编程 “提高性能” 应尽力做到
    java中Set类接口的用法
    oc-可变数组继承不可变数组
    oc-数组内元素排序
    oc-数组遍历
    oc-创建数组
    oc-字典应用
    oc-数组应用及相关练习
  • 原文地址:https://www.cnblogs.com/clrs97/p/8587043.html
Copyright © 2020-2023  润新知