P3813 [FJOI2017] 矩阵填数 题解

考虑容斥,枚举哪些矩阵中的数 \(<v\)(个数为 \(c\)),哪些 \(\le v\),则系数为 \((-1)^c\)

考虑将矩阵离散化为 \(\mathcal O(n^2)\) 个块,对于每个子矩阵枚举覆盖的块,更新最大值,最后答案便是 \(\sum_{T\sub S}(-1)^{|T|}\prod_{block}\max_{block}^{size_{block}}\)

参考代码:

#include<bits/stdc++.h>
#define ll long long
#define md 1000000007
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int T,h,w,m,n,t1,t2,d1[23],d2[23],f[23][23];
ll ans;
struct node{
	int x1,y1,x2,y2,c;
	inline void in(){
		scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
		d1[++t1]=x1,d1[++t1]=x2+1;
		d2[++t2]=y1,d2[++t2]=y2+1;
	}
}a[12];
ll power(ll x,int y){
	ll ans=1;
	for(;y;y>>=1){
		if(y&1)ans=ans*x%md;
		x=x*x%md;
	}
	return ans;
}
ll solve(int s){
	rept(i,1,t1)rept(j,1,t2)f[i][j]=m;
	rept(i,0,n){
		int c=((s>>i)&1)?a[i].c-1:a[i].c;
		int x1=lower_bound(d1+1,d1+t1+1,a[i].x1)-d1,x2=lower_bound(d1+1,d1+t1+1,a[i].x2+1)-d1;
		int y1=lower_bound(d2+1,d2+t2+1,a[i].y1)-d2,y2=lower_bound(d2+1,d2+t2+1,a[i].y2+1)-d2;
		rept(x,x1,x2)rept(y,y1,y2)f[x][y]=min(f[x][y],c);
	}
	ll ans=1;
	rept(i,1,t1)rept(j,1,t2){
		ans=ans*power(f[i][j],(d1[i+1]-d1[i])*(d2[j+1]-d2[j]))%md;
	}
	return ans;
}
signed main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d%d",&h,&w,&m,&n);
		t1=t2=2,d1[1]=d2[1]=1,d1[2]=h+1,d2[2]=w+1;
		rept(i,0,n)a[i].in();
		sort(d1+1,d1+t1+1);t1=unique(d1+1,d1+t1+1)-d1-1;
		sort(d2+1,d2+t2+1);t2=unique(d2+1,d2+t2+1)-d2-1;
		ans=0;
		rept(s,0,1<<n){
			if(__builtin_popcount(s)&1)ans=(ans-solve(s))%md;
			else ans=(ans+solve(s))%md;
		}
		cout<<(ans+md)%md<<'\n';
	}
	return 0;
}
posted @ 2025-07-06 19:36  zifanwang  阅读(19)  评论(0)    收藏  举报