【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; }