【LOJ】#2280. 「FJOI2017」矩阵填数

题解

我们发现没有限制的小方格可以随便填

然后考虑有限制的,我们把它切割成一个个小块(枚举相邻的横纵坐标),然后记录一下这个小块的最大值限制(也就是所有覆盖它的矩形最小的最大值)
记录一下每个小块的大小,和每个小块在哪些有限制的大矩形,且小块的最大值限制等于大矩形的最大值限制,用一个二进制数表示
然后可以状压dp了,每次枚举这个小块里面填不填最大值,填了就是\(V^{n} - (V - 1)^{n}\)不填就是\((V - 1)^{n}\)

代码

#include <bits/stdc++.h>
#define MAXN 500005
//#define ivorysi
#define enter putchar('\n')
#define space putchar(' ')
#define fi first
#define se second
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {putchar('-');x = -x;}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
const int MOD = 1000000007;
int T;
int N,H,W,Q,numx[45],numy[45],cnt,cov[505],cal[505],val[505],tot,ans;
int f[505][(1 << 10) + 5];
struct node {
    int x1,x2,y1,y2,val;
}M[15];
int inc(int a,int b) {
    a = a + b;
    if(a >= MOD) a -= MOD;
    return a;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
int fpow(int x,int c) {
    int res = 1,t = x;
    while(c) {
    if(c & 1) res = mul(res,t);
    t = mul(t,t);
    c >>= 1;
    }
    return res;
}
void pre() {
    sort(numx + 1,numx + cnt + 1);
    sort(numy + 1,numy + cnt + 1);
    memset(cov,0,sizeof(cov));
    memset(cal,0,sizeof(cal));
    tot = 0;
    for(int i = 1 ; i <= cnt ; ++i) {
    for(int j = 1 ; j <= cnt ; ++j) {
        int sx = numx[i - 1] + 1,sy = numy[j - 1] + 1;
        int tx = numx[i],ty = numy[j];
        if(sx > tx || sy > ty) continue;
        int v = Q;
        bool flag = 0;
        for(int k = 1 ; k <= N ; ++k) {
        if(sx >= M[k].x1 && tx <= M[k].x2 && sy >= M[k].y1 && ty <= M[k].y2) {
            v = min(v,M[k].val);
            flag = 1;
        }
        }
        if(!flag) {
        ans = mul(ans,fpow(Q,(tx - sx + 1) * (ty - sy + 1)));
        continue;
        }
        ++tot;cal[tot] = (tx - sx + 1) * (ty - sy + 1);val[tot] = v;
        for(int k = 1 ; k <= N ; ++k) {
        if(v == M[k].val) {
            if(sx >= M[k].x1 && tx <= M[k].x2 && sy >= M[k].y1 && ty <= M[k].y2) {
            cov[tot] |= 1 << (k - 1);
            }
        }
        }
    }
    }
}
void Solve() {
    read(H);read(W);read(Q);read(N);
    cnt = 0;
    ans = 1;
    for(int i = 1 ; i <= N ; ++i) {
    read(M[i].x1);read(M[i].y1);read(M[i].x2);read(M[i].y2);read(M[i].val);
    numx[++cnt] = M[i].x1 - 1;numy[cnt] = M[i].y1 - 1;
    numx[++cnt] = M[i].x2;numy[cnt] = M[i].y2;
    }
    numx[++cnt] = 0;numy[cnt] = 0;
    numx[++cnt] = H;numy[cnt] = W;
    pre();
    memset(f,0,sizeof(f));
    f[0][0] = 1;
    for(int i = 1 ; i <= tot ; ++i) {
    for(int S = 0 ; S < (1 << N) ; ++S) {
        f[i][S | cov[i]] = inc(f[i][S | cov[i]],mul(f[i - 1][S],inc(fpow(val[i],cal[i]),MOD - fpow(val[i] - 1,cal[i]))));
        f[i][S] = inc(f[i][S],mul(f[i - 1][S],fpow(val[i] - 1,cal[i])));
    }
    }
    ans = mul(ans,f[tot][(1 << N) - 1]);
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(T);
    while(T--) {
    Solve();
    }
    return 0;
}

转载于:https://www.cnblogs.com/ivorysi/p/9150710.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值