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 
View Code

 

posted @ 2017-09-11 13:58  Blue233333  阅读(461)  评论(0编辑  收藏  举报