[FJOI2017] 矩阵填数
标签:容斥
[FJOI2017]矩阵填数
题目描述
给定一个
在这个矩阵中你需要在每个格子中填入
给这个矩阵填数的时候有一些限制,给定
现在,你的任务是求出有多少种填数的方案满足
两种方案是不一样的当且仅当两个方案至少存在一个格子上有不同的数。由于答案可能很大,你只需要输出答案对
其中,
思路点拨
我们观察数据范围可以发现,
看到限制:这个限制可以转化为一个子矩阵内,所有的数都不可以超过
子矩阵怎么处理?难道要些什么十分恶心的数据结构?K-d tree?数树套树?不对,
时空复杂度分析:时间
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-f;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int MAXN=1e4+10;
const int mod=1e9+7;
int T,n,m,k,q;
int posx[MAXN],posy[MAXN],tot1,tot2;
struct node{
int x1,y1,x2,y2;
int w;
}a[MAXN],b[MAXN];
bool check(node A,node B){
if(A.x1<=B.x1&&B.x2<=A.x2&&A.y1<=B.y1&&B.y2<=A.y2) return 1;
return 0;
}
void clear(){
memset(posx,0,sizeof(posx));
memset(posy,0,sizeof(posy));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
}
int qpow(int a,int b){
int ans=1,base=a;
while(b){
if(b&1) ans=(ans*base)%mod;
base=(base*base)%mod;
b>>=1;
}
return ans;
}
signed main(){
T=read();
while(T--){
clear();
n=read(),m=read(),k=read(),q=read();//矩阵长宽,值域上限,限制数量
tot1=tot2=0;
for(int i=1;i<=q;i++){
posx[++tot1]=b[i].x1=read();
posx[tot1]--;
posy[++tot2]=b[i].y1=read();
posy[tot2]--;
posx[++tot1]=b[i].x2=read();
posy[++tot2]=b[i].y2=read();
b[i].w=read();
}
posx[++tot1]=n;
posy[++tot2]=m;
sort(posx+1,posx+tot1+1);
sort(posy+1,posy+tot2+1);
tot1=unique(posx+1,posx+tot1+1)-posx-1;
tot2=unique(posy+1,posy+tot2+1)-posy-1;
int lasx=1,lasy,cnt=0;
for(int i=1;i<=tot1;i++){
if(!posx[i]) continue;
lasy=1;
for(int j=1;j<=tot2;j++){
if(!posy[j]) continue;
++cnt;
a[cnt].x1=lasx,a[cnt].y1=lasy;
a[cnt].x2=posx[i],a[cnt].y2=posy[j];
a[cnt].w=k;
lasy=posy[j]+1;
}
lasx=posx[i]+1;
}
int ans=0;
for(int i=0;i<(1<<q);i++){
int popcount=0;
for(int j=0;j<q;j++)
if(i&(1<<j))
popcount++;
for(int j=1;j<=cnt;j++)
a[j].w=k;
for(int j=1;j<=q;j++){
int opt=0;
if(i&(1<<(j-1))) opt++;
for(int z=1;z<=cnt;z++)
if(check(b[j],a[z]))
a[z].w=min(a[z].w,b[j].w-opt);
}
int sum=1;
for(int j=1;j<=cnt;j++){
int siz=(a[j].x2-a[j].x1+1)*(a[j].y2-a[j].y1+1);
sum=(sum*qpow(a[j].w,siz))%mod;
}
if(popcount&1) ans=(ans-sum+mod)%mod;
else ans=(ans+sum)%mod;
}
cout<<ans<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现