BZOJ5010: [Fjoi2017]矩阵填数
Posted Blue233333
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ5010: [Fjoi2017]矩阵填数相关的知识,希望对你有一定的参考价值。
h<=10000 * w<=10000的矩阵,每个格填不超过m<=10000的数,外加n<=10的限制,描述n个子矩阵中最大值一定要是多少,求方案数。
首先一块地能填的数就是1~这块地经过多重矩形覆盖后的最小值,然后要排除那些规定矩形填不到最大值的情况,所以答案为:每块地都满足<=该块地被限制矩形覆盖后的最小值的方案-所有一块地<该块地被限制矩形覆盖后的最小值的方案(即“某一个一定不满足条件的方案”)+所有两块地<该块地被限制矩形覆盖后的最小值的方案(即“某两个一定不满足条件的方案”)-+-+……,就是容斥。
由于要进行矩形的覆盖并且统计每个数据出现的次数来计算答案,就把坐标离散化一波,并把离散化后切成的每一块矩形的面积处理出来。为了方便,把按离散化后坐标切成的矩形标记为左开右闭(或左闭右开)。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 //#include<iostream> 6 using namespace std; 7 8 int h,w,m,n; 9 int xx[23],yy[23],vv[23],lx=0,ly=0,lv=0; 10 struct mat{int x1,x2,y1,y2,v;}a[23]; 11 const int mod=1e9+7; 12 int mp[23][23],re[23][23],cnt[23]; 13 int powmod(int a,int b) 14 { 15 int ans=1,tmp=a; 16 while (b) {if (b&1) ans=1ll*ans*tmp%mod;tmp=1ll*tmp*tmp%mod;b>>=1;} 17 return ans; 18 } 19 int t; 20 int main() 21 { 22 scanf("%d",&t); 23 while (t--) 24 { 25 scanf("%d%d%d%d",&h,&w,&m,&n); 26 xx[lx=1]=0;xx[lx=2]=h; 27 yy[ly=1]=0;yy[ly=2]=w; 28 vv[lv=1]=m; 29 for (int i=1;i<=n;i++) 30 { 31 scanf("%d%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2,&a[i].v); 32 a[i].x1--;a[i].y1--; 33 xx[++lx]=a[i].x1;xx[++lx]=a[i].x2; 34 yy[++ly]=a[i].y1;yy[++ly]=a[i].y2; 35 vv[++lv]=a[i].v;vv[++lv]=a[i].v-1; 36 } 37 sort(xx+1,xx+1+lx);sort(yy+1,yy+1+ly);sort(vv+1,vv+1+lv); 38 lx=unique(xx+1,xx+1+lx)-xx-1;ly=unique(yy+1,yy+1+ly)-yy-1;lv=unique(vv+1,vv+1+lv)-vv-1; 39 for (int i=1;i<=lx;i++) 40 for (int j=1;j<=ly;j++) 41 re[i][j]=(xx[i]-xx[i-1])*(yy[j]-yy[j-1]); 42 for (int i=1;i<=n;i++) 43 { 44 a[i].x1=lower_bound(xx+1,xx+1+lx,a[i].x1)-xx; 45 a[i].y1=lower_bound(yy+1,yy+1+ly,a[i].y1)-yy; 46 a[i].x2=lower_bound(xx+1,xx+1+lx,a[i].x2)-xx; 47 a[i].y2=lower_bound(yy+1,yy+1+ly,a[i].y2)-yy; 48 a[i].v=lower_bound(vv+1,vv+1+lv,a[i].v)-vv; 49 } 50 int ans=0; 51 for (int s=0;s<(1<<n);s++) 52 { 53 for (int j=1;j<=lx;j++) 54 for (int k=1;k<=ly;k++) 55 mp[j][k]=lv; 56 int now=1; 57 for (int i=1;i<=n;i++) 58 { 59 int v=a[i].v; 60 if ((s>>(i-1))&1) now=-now,v--; 61 for (int j=a[i].x1+1;j<=a[i].x2;j++) 62 for (int k=a[i].y1+1;k<=a[i].y2;k++) 63 mp[j][k]=min(mp[j][k],v); 64 } 65 memset(cnt,0,sizeof(cnt)); 66 for (int i=1;i<=lx;i++) 67 for (int j=1;j<=ly;j++) 68 cnt[mp[i][j]]+=re[i][j]; 69 for (int i=1;i<=lv;i++) if (cnt[i]) now=1ll*now*powmod(vv[i],cnt[i])%mod; 70 ans=(ans+now)%mod; 71 } 72 printf("%d\n",(ans+mod)%mod); 73 } 74 return 0; 75 } 76
以上是关于BZOJ5010: [Fjoi2017]矩阵填数的主要内容,如果未能解决你的问题,请参考以下文章