【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;
    }
    
    
posted @ 2019-06-26 22:12  大米饼  阅读(445)  评论(0编辑  收藏  举报