【题解】[FJOI2017]矩阵填数
题目分析:
最大值为 的限制显然可以转化为 的方案数减去 的方案数。
因为这里有很多个这种限制所以直接容斥就好了,具体来说就是枚举哪些条件取 那么剩下的就取 ,取 手算一下就可以得到容斥系数为 。
因为 所以其实对于某一种情况求方案直接暴力就可以了,我们可以将矩阵离散化,这样会用到的点就只有 个,我们可以对于每一个位置求一下其取值范围,下界显然就是 了,而对于上界我们其实就可以将这些限制从紧到松去取,也就是从小到大排序,然后每次进行一个矩阵赋值和矩阵求和,这样限制出来显然是正确的。
代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 105;
const int MOD = 1e9+7;
struct node{
int l1,l2,r1,r2,v;
}a[N],b[N];
int cnt[N][N],l[N],r[N];
bool vis[N][N];
int mod(int x){
return x % MOD;
}
int power(int a,int b){
int res = 1;
while(b){
if(b & 1) res = mod(res * a);
a = mod(a * a);
b >>= 1;
}
return res;
}
bool cmp(node a,node b){
return a.v < b.v;
}
int calc(int l1,int r1,int l2,int r2){
int res = 0;
for(int i=l1; i<l2; i++){
for(int j=r1; j<r2; j++){
if(!vis[i][j]){
res += cnt[i][j];
vis[i][j] = true;
}
}
}
return res;
}
signed main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;scanf("%lld",&T);
while(T--){
memset(cnt,0,sizeof(cnt));memset(vis,false,sizeof(vis));
int n,m,limit,h;scanf("%lld%lld%lld%lld",&n,&m,&limit,&h);
int cnt1 = 0,cnt2 = 0;
l[++cnt1] = 1;l[++cnt1] = n+1;
r[++cnt2] = 1;r[++cnt2] = m+1;
for(int i=1; i<=h; i++){
scanf("%lld%lld%lld%lld%lld",&a[i].l1,&a[i].r1,&a[i].l2,&a[i].r2,&a[i].v);
a[i].l2++,a[i].r2++;
l[++cnt1] = a[i].l1;l[++cnt1] = a[i].l2;
r[++cnt2] = a[i].r1;r[++cnt2] = a[i].r2;
}
sort(l+1,l+cnt1+1);sort(r+1,r+cnt2+1);
cnt1 = unique(l+1,l+cnt1+1) - l - 1;
cnt2 = unique(r+1,r+cnt2+1) - r - 1;
for(int i=1; i<=h; i++){
a[i].l1 = lower_bound(l+1,l+cnt1+1,a[i].l1) - l;
a[i].r1 = lower_bound(r+1,r+cnt2+1,a[i].r1) - r;
a[i].l2 = lower_bound(l+1,l+cnt1+1,a[i].l2) - l;
a[i].r2 = lower_bound(r+1,r+cnt2+1,a[i].r2) - r;
}
for(int i=1; i<cnt1; i++){ //我们将每一个点代表它右下角的这一块
for(int j=1; j<cnt2; j++){
cnt[i][j] = mod((l[i+1] - l[i]) * (r[j+1] - r[j]));
}
}
int ans = 0;
for(int S=0; S<(1<<h); S++){
for(int i=1; i<cnt1; i++){
for(int j=1; j<cnt2; j++){
vis[i][j] = false;
}
}
int res = 1;
for(int i=1; i<=h; i++){
b[i] = a[i];
if((S >> (i-1)) & 1) b[i].v--;
}
sort(b+1,b+h+1,cmp);
for(int i=1; i<=h; i++) res = mod(res * power(b[i].v,calc(b[i].l1,b[i].r1,b[i].l2,b[i].r2)));
for(int i=1; i<cnt1; i++){
for(int j=1; j<cnt2; j++){
if(vis[i][j]) continue;
res = mod(res * power(limit,cnt[i][j]));
}
}
if(__builtin_parity(S)) ans = mod(ans + (MOD-1) * res);
else ans = mod(ans + res);
}
printf("%lld\n",ans);
}
return 0;
}
标签:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律