BZOJ5010 FJOI2017矩阵填数(容斥原理)
如果只考虑某个子矩阵的话,其最大值为v的方案数显然是vsize-(v-1)size。问题在于处理子矩阵间的交叉情况。
如果两个交叉的子矩阵所要求的最大值不同,可以直接把交叉部分划给所要求的最大值较小的子矩阵。那么,所要求最大值不同的格子彼此间是独立的。于是现在可以只考虑要求相同的格子。
直接计算似乎很麻烦。由于n很小,考虑一个很套路的容斥:至少0个不满足限制的方案数-至少1个不满足限制的方案数+至少2个不满足限制的方案数……于是我们可以枚举哪些矩阵不满足限制,剩下的随便填(当然要在所限制的最大值之内)。
计算这些矩形的交和并也是一个有点麻烦的问题。可以离散化后暴力统计。这里离散化后应该每个位置表示一段区间比较方便,所以读入时++x2,++y2。由于数据范围实在太小怎么做都行。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define P 1000000007
#define N 13
#define y1 y3
#define y2 y4
int T,r,c,n,m,row[N<<],line[N<<],flag[N<<][N<<],ans,sum,nw,nv;
bool choose[N];
struct data
{
int x1,y1,x2,y2,v,size;
int tag[N<<][N<<];
bool operator <(const data&a) const
{
return v>a.v;
}
}a[N];
int ksm(int a,int k)
{
if (k==) return ;
int tmp=ksm(a,k>>);
if (k&) return 1ll*tmp*tmp%P*a%P;
else return 1ll*tmp*tmp%P;
}
int calc(int v)
{
memset(flag,,sizeof(flag));
for (int i=;i<=n;i++)
if (a[i].v==v&&!choose[i])
for (int j=a[i].x1;j<a[i].x2;j++)
for (int k=a[i].y1;k<a[i].y2;k++)
if (a[i].tag[j][k]) flag[j][k]=;
for (int i=;i<=n;i++)
if (choose[i])
for (int j=a[i].x1;j<a[i].x2;j++)
for (int k=a[i].y1;k<a[i].y2;k++)
if (a[i].tag[j][k]) flag[j][k]=-;
int s1=,s2=;
for (int i=;i<nw;i++)
for (int j=;j<nv;j++)
if (flag[i][j]==) s1+=(row[i+]-row[i])*(line[j+]-line[j]);
else if (flag[i][j]==-) s2+=(row[i+]-row[i])*(line[j+]-line[j]);
return 1ll*ksm(v,s1)*ksm(v-,s2)%P;
}
void dfs(int k,int s,int v)
{
if (k>n)
{
if (s&) sum=(sum-calc(v)+P)%P;
else sum=(sum+calc(v))%P;
return;
}
if (a[k].v==v) choose[k]=,dfs(k+,s+,v);
choose[k]=;dfs(k+,s,v);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj5010.in","r",stdin);
freopen("bzoj5010.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
T=read();
while (T--)
{
r=read(),c=read(),m=read(),n=read();
for (int i=;i<=n;i++)
a[i].x1=read(),a[i].y1=read(),a[i].x2=read()+,a[i].y2=read()+,a[i].v=read(),a[i].size=,memset(a[i].tag,,sizeof(a[i].tag));
int w=,v=;
for (int i=;i<=n;i++)
row[++w]=a[i].x1,row[++w]=a[i].x2,line[++v]=a[i].y1,line[++v]=a[i].y2;
row[++w]=,row[++w]=r+;line[++v]=,line[++v]=c+;
sort(row+,row+w+);sort(line+,line+v+);
nw=unique(row,row+w+)-row-,nv=unique(line,line+v+)-line-;
for (int i=;i<=n;i++)
a[i].x1=lower_bound(row+,row+nw+,a[i].x1)-row,a[i].x2=lower_bound(row+,row+nw+,a[i].x2)-row,
a[i].y1=lower_bound(line+,line+nv+,a[i].y1)-line,a[i].y2=lower_bound(line+,line+nv+,a[i].y2)-line;
sort(a+,a+n+);
memset(flag,,sizeof(flag));
for (int i=;i<=n;i++)
for (int j=a[i].x1;j<a[i].x2;j++)
for (int k=a[i].y1;k<a[i].y2;k++)
flag[j][k]=a[i].v;
for (int i=;i<=n;i++)
for (int j=;j<nw;j++)
for (int k=;k<nv;k++)
if (flag[j][k]==a[i].v) a[i].size++,a[i].tag[j][k]=;
ans=;
for (int i=;i<nw;i++)
for (int j=;j<nv;j++)
if (flag[i][j]==) ans=1ll*ans*ksm(m,(row[i+]-row[i])*(line[j+]-line[j]))%P;
for (int i=;i<=n;i++)
{
sum=;int t=i;
while (a[t+].v==a[i].v) t++;
memset(choose,,sizeof(choose));
dfs(i,,a[i].v);
ans=1ll*ans*sum%P;
i=t;
}
cout<<ans<<endl;
}
return ;
}
BZOJ5010 FJOI2017矩阵填数(容斥原理)的更多相关文章
- [BZOJ5010][FJOI2017]矩阵填数(状压DP)
5010: [Fjoi2017]矩阵填数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 90 Solved: 45[Submit][Status][ ...
- bzoj5010: [Fjoi2017]矩阵填数
Description 给定一个 h*w 的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w.在这个矩阵中你需要在每 个格子中填入 1..m 中的某个数.给这个矩阵填数的时候有一 ...
- P3813 [FJOI2017]矩阵填数(组合数学)
P3813 [FJOI2017]矩阵填数 shadowice1984说:看到计数想容斥........ 这题中,我们把图分成若干块,每块的最大值域不同 蓝后根据乘法原理把每块的方案数(互不相干)相乘. ...
- [FJOI2017]矩阵填数——容斥
参考:题解 P3813 [[FJOI2017]矩阵填数] 题目大意: 给定一个 h∗w 的矩阵,矩阵的行编号从上到下依次为 1...h ,列编号从左到右依次 1...w . 在这个矩阵中你需要在每个格 ...
- [luogu P3813] [FJOI2017] 矩阵填数 解题报告 (容斥原理)
题目链接: https://www.luogu.org/problemnew/show/P3813 题目: 给定一个 h*w的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w. ...
- bzoj 5010: [Fjoi2017]矩阵填数
Description 给定一个 h*w 的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w.在这个矩阵中你需要在每 个格子中填入 1..m 中的某个数.给这个矩阵填数的时候有一 ...
- 【BZOJ】5010: [Fjoi2017]矩阵填数
[算法]离散化+容斥原理 [题意]给定大矩阵,可以每格都可以任意填1~m,给定n个子矩阵,要求满足子矩阵内的最大值为vi,求方案数. n<=10,h,w<=1w. [题解] 此题重点之一在 ...
- P3813 [FJOI2017]矩阵填数
传送门 矩阵很大,但是发现 $n$ 很小,从这边考虑,对于一个一堆小矩阵放在一起的情况 考虑把每一块单独考虑然后方案再乘起来 但是这些奇怪的东西很不好考虑 所以暴力一点,直接拆成一个个小块 但是这样我 ...
- [FJOI2017]矩阵填数
[Luogu3813] [LOJ2280] 写得很好的题解 \(1.\)离散化出每一块内部不互相影响的块 \(2.\)\(dp[i][j]\)为前 \(i\) 种重叠块其中有 \(j\) 这些状态的矩 ...
随机推荐
- SpringMVC异常处理方式
一.描述 在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的.不可预知的异常需要处理.每个过程都单独处理异常,系统的代码耦合 ...
- Android 解决布局无法对齐的情况
是这样的,在为app制作titlebar或者使用RadioGroup设置布局的的weight属性后,会出现有些机型的手机布局无法居中的问题. 在遇到这类问题时,大部分的原因就是因为没有设置控件的属性: ...
- 异步方法(promise版)出错自调用
/** * [*promisePlus promise封装的异步,既然是异步,必然会成功或者失败,理论上失败了就失败了,但是 * 失败后能否让他过多长时间自动再调用自己呢,如果调用指定的次数还是失败, ...
- 初识Identity(一)
一.Authentication(身份验证)和Authorization(授权) 如何构建安全的web应用?authentication和authorization是asp.net中最重要最基本的防护 ...
- 【LeetCode191】Number of 1 Bits★
1.题目 2.思路 方法一:常规方法. 方法二:给面试官惊喜的解法. 3.java代码 方法一代码: public class Solution { // you need to treat n as ...
- Luogu2792 JSOI2008 小店购物 最小树形图
传送门 被题意杀 本以为一个种类的物品一定要一起买 看了题解才知道可以先把所有要买的物品买一个,剩下要买的物品就可以得到这个种类的物品能够得到的最大优惠-- 所以现在只需要知道:第一次买所有物品一遍时 ...
- .NetCore实践篇:成功解决分布式监控ZipKin聚合依赖问题(三)
前言 读本篇文章之前,可以先读前两篇文章.为了照顾没看过的朋友,我也会稍作复习. 思考大纲: .Net架构篇:思考如何设计一款实用的分布式监控系统? 实践篇一:.NetCore实践篇:分布式监控客户端 ...
- oracle如何导出和导入数据库/表
oracle如何导出和导入数据库/表 oracle如何将项目中的表导出后在导入自己的数据库中,这是一个完整的操作,对于数据库备份或在本地查看数据验证数据进场用到,一般情况下我都用dos黑窗口进行操作, ...
- Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)-C-Bracket Subsequence
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> ...
- Sprint 冲刺第三阶段第二天
陈汝婷:播放音乐 1:做播放音乐这个功能时开始没有考虑周全,使用 PS P出来的图竟然没有用上,耗时耗人工.吃一见长一智,以后要考虑周全.还要耗了那么久,音乐的初效果终于出来了. 2:昨天出现的问题, ...