【JZOJ6230】【20190625】梦批糼

题目

一个$n\times m \times l $的立方体,有一些位置有障碍

一次操作会随机选择一个立方体,共有\(w\)次操作

询问所有操作都不选到障碍点,被选到至少一次的点的期望

$n ,m,l \le 60 ,  w \le 10^9 $

题解

  • 只需要计算不包含障碍且包含一个点的立方体个数

  • 40pts

  • 枚举每一个立方体,前缀和判断一个立方体中是否有障碍,差分统计一个点被多少个立方体包含

  • 时间复杂度:\(O(n^6)\)

  • 100pts

  • \(dp[0-7][x][y][z]\) 表示八个方向的立方体个数

  • 枚举立方体层的范围,将这些层的障碍或起来压成一层

  • 变成在二维上统计矩形的个数,用单调栈即可

  • 前缀和之后可以求出\(dp\),答案可以用\(dp\)统计

  • 时间复杂度:\(O(n^4)\)

    \(O(n^6)\)

    #include<bits/stdc++.h>
    #define mod 998244353
    const int N=100;
    using namespace std;
    int n,m,l,w,a[N][N][N],s[N][N][N],ans,cnt,v[N][N][N],c[N][N][N];
    void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
    
    int pw(int x,int y){
      int re=1;
      while(y){
          if(y&1)re=1ll*re*x%mod;
          y>>=1;x=1ll*x*x%mod;
      }return re;
    }
    
    int cal1(int x){return x*(x+1)/2;}
    int cal2(int i1,int j1,int k1,int i2,int j2,int k2){
      return s[i2][j2][k2]
      -s[i1-1][j2][k2]-s[i2][j1-1][k2]-s[i2][j2][k1-1]
      +s[i1-1][j1-1][k2]+s[i1-1][j2][k1-1]+s[i2][j1-1][k1-1]
      -s[i1-1][j1-1][k1-1];
    }
    void put(int i1,int j1,int k1,int i2,int j2,int k2){
      c[i1][j1][k1]++;
      c[i2+1][j1][k1]--;c[i1][j2+1][k1]--;c[i1][j1][k2+1]--;
      c[i2+1][j2+1][k1]++;c[i2+1][j1][k2+1]++;c[i1][j2+1][k2+1]++;
      c[i2+1][j2+1][k2+1]--;
    }
    void pre(){
      for(int i=1;i<=n;++i)
      for(int j=1;j<=m;++j)
      for(int k=1;k<=l;++k){
          s[i][j][k] = 
              a[i][j][k]
              +s[i-1][j][k]+s[i][j-1][k]+s[i][j][k-1]
              -s[i-1][j-1][k]-s[i-1][j][k-1]-s[i][j-1][k-1]
              +s[i-1][j-1][k-1];
      }
      for(int i1=1;i1<=n;++i1)
      for(int j1=1;j1<=m;++j1)
      for(int k1=1;k1<=l;++k1){
          for(int i2=i1;i2<=n;++i2){
              if(cal2(i1,j1,k1,i2,j1,k1))break;
              for(int j2=j1;j2<=m;++j2){
                  if(cal2(i1,j1,k1,i2,j2,k1))break;
                      for(int k2=k1;k2<=l;++k2){
                          if(cal2(i1,j1,k1,i2,j2,k2))break;
                          put(i1,j1,k1,i2,j2,k2); 
                          cnt++;
                  }
              }
          }
      }
      for(int i=1;i<=n;++i)
      for(int j=1;j<=m;++j)
      for(int k=1;k<=l;++k){
          c[i][j][k] = 
          c[i][j][k]
          +c[i-1][j][k]+c[i][j-1][k]+c[i][j][k-1]
          -c[i-1][j-1][k]-c[i-1][j][k-1]-c[i][j-1][k-1]
          +c[i-1][j-1][k-1];
      }
    }
    int main(){
      freopen("dream.in","r",stdin);
      freopen("dream.out","w",stdout);
      scanf("%d%d%d%d",&n,&m,&l,&w);
      for(int i=1;i<=n;++i)
      for(int j=1;j<=m;++j)
      for(int k=1;k<=l;++k)scanf("%d",&a[i][j][k]),a[i][j][k]^=1;
      for(int i=1;i<=n;++i)
      for(int j=1;j<=m;++j)
      for(int k=1;k<=l;++k)scanf("%d",&v[i][j][k]);
      pre();
      int ip=pw(1ll*cal1(n)*cal1(m)%mod*cal1(l)%mod,mod-2);
      int tmp=pw(1ll*cnt*ip%mod,w);
      for(int I=1;I<=n;++I)
      for(int J=1;J<=m;++J)
      for(int K=1;K<=l;++K)if(!a[I][J][K]){
          a[I][J][K]=1;
          inc(ans,1ll*v[I][J][K]*(tmp-pw(1ll*(cnt-c[I][J][K]+mod)*ip%mod,w)+mod)%mod);
          a[I][J][K]=0;
      }
      cout<<ans<<endl;
    }

    \(O(n^4)\)

    #include<bits/stdc++.h>
    #define mod 998244353
    #define ll long long 
    using namespace std;
    const int N=110;
    int n,m,l,w,a[N][N][N],v[N][N][N],s[8][N][N][N],c[N][N],d[N],st[N],f[N],tp,sum,ans;
    void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
    int pw(int x,int y){
      int re=1;
      while(y){
          if(y&1)re=(ll)re*x%mod;
          y>>=1;x=(ll)x*x%mod;
      }return re;
    }
    void ins(int x){
      while(tp&&d[x]<=d[st[tp]])tp--;
      sum=f[tp]+abs(x-st[tp])*d[x];
      st[++tp]=x,f[tp]=sum;
    }
    void cal1(int t,int i1,int j1,int k1){
      int i2=t&1?i1+1:i1-1,j2=t&2?j1+1:j1-1,k2=t&4?k1+1:k1-1;
      s[t][i1][j1][k1]=
          (0ll+
           s[t][i1][j1][k1]
          +s[t][i2][j1][k1]+s[t][i1][j2][k1]+s[t][i1][j1][k2]
          -s[t][i1][j2][k2]-s[t][i2][j1][k2]-s[t][i2][j2][k1]
          +s[t][i2][j2][k2]
          )%mod;
    }
    //三维前缀和
    int cal2(int i1,int j1,int k1){
      ll re=
           s[6][i1-1][1][1]+s[7][i1+1][1][1]
           +s[5][1][j1-1][1]+s[7][1][j1+1][1]
           +s[3][1][1][k1-1]+s[7][1][1][k1+1]
           -s[2][i1-1][1][k1-1]-s[3][i1+1][1][k1-1]-s[7][i1+1][1][k1+1]-s[6][i1-1][1][k1+1]
           -s[4][i1-1][j1-1][1]-s[5][i1+1][j1-1][1]-s[7][i1+1][j1+1][1]-s[6][i1-1][j1+1][1]
           -s[1][1][j1-1][k1-1]-s[3][1][j1+1][k1-1]-s[7][1][j1+1][k1+1]-s[5][1][j1-1][k1+1]
           +s[0][i1-1][j1-1][k1-1]+s[1][i1+1][j1-1][k1-1]+s[2][i1-1][j1+1][k1-1]+s[3][i1+1][j1+1][k1-1]
           +s[4][i1-1][j1-1][k1+1]+s[5][i1+1][j1-1][k1+1]+s[6][i1-1][j1+1][k1+1]+s[7][i1+1][j1+1][k1+1]
          ;
      return re%mod;
    }
    //四个卦限-两个卦限+一个卦限
    int main(){
      freopen("dream.in","r",stdin);
      freopen("dream.out","w",stdout);
      scanf("%d%d%d%d",&n,&m,&l,&w);
      for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)for(int k=1;k<=l;++k)scanf("%d",&a[i][j][k]);
      for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)for(int k=1;k<=l;++k)scanf("%d",&v[i][j][k]);
      for(int i1=1;i1<=n;++i1)
      for(int i2=i1;i2<=n;++i2){
          for(int j=1;j<=m;++j)for(int k=1;k<=l;++k)
              c[j][k]=i1==i2?a[i1][j][k]:c[j][k]&a[i2][j][k];
          for(int k=1;k<=l;++k)d[k]=0;
          for(int j=1;j<=m;++j){
              for(int k=1;k<=l;++k)
                  if(c[j][k])d[k]++;else d[k]=0;
              st[sum=tp=0]=0;
              for(int k=1;k<=l;++k){
                  ins(k);
                  s[1][i1][j][k]+=sum;
                  s[0][i2][j][k]+=sum;
              }
              st[sum=tp=0]=l+1;
              for(int k=l;k>=1;--k){
                  ins(k);
                  s[5][i1][j][k]+=sum;
                  s[4][i2][j][k]+=sum;
              }
          }
          for(int k=1;k<=l;++k)d[k]=0;
          for(int j=m;j>=1;--j){
              for(int k=1;k<=l;++k)
                  if(c[j][k])d[k]++;else d[k]=0;
              st[sum=tp=0]=0;
              for(int k=1;k<=l;++k){
                  ins(k);
                  s[3][i1][j][k]+=sum;
                  s[2][i2][j][k]+=sum;
              }
              st[sum=tp=0]=l+1;
              for(int k=l;k>=1;--k){
                  ins(k);
                  s[7][i1][j][k]+=sum;
                  s[6][i2][j][k]+=sum;
              }
          }
    
      }
      for(int i=1;i<=n;++i){
          for(int j=1;j<=m;++j){
              for(int k=1;k<=l;++k)cal1(0,i,j,k);
              for(int k=l;k>=1;--k)cal1(4,i,j,k);
          }
          for(int j=m;j>=1;--j){
              for(int k=1;k<=l;++k)cal1(2,i,j,k);
              for(int k=l;k>=1;--k)cal1(6,i,j,k);
          }
      }
      for(int i=n;i>=1;--i){
          for(int j=1;j<=m;++j){
              for(int k=1;k<=l;++k)cal1(1,i,j,k);
              for(int k=l;k>=1;--k)cal1(5,i,j,k);
          }
          for(int j=m;j>=1;--j){
              for(int k=1;k<=l;++k)cal1(3,i,j,k);
              for(int k=l;k>=1;--k)cal1(7,i,j,k);
          }
      }
      int tmp=pw(s[7][1][1][1],w);
      for(int i=1;i<=n;++i)
      for(int j=1;j<=m;++j)
      for(int k=1;k<=l;++k)if(a[i][j][k]){
          inc(ans , 1ll * v[i][j][k] * (tmp-pw(cal2(i,j,k),w)+mod) %mod);
      }
      ans=1ll*ans*pw(1ll*n*m*l*(n+1)*(m+1)*(l+1)/8%mod,mod-1-w)%mod;
      cout<<ans<<endl;
      return 0;
    }
    

转载于:https://www.cnblogs.com/Paul-Guderian/p/11094230.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值