zoukankan      html  css  js  c++  java
  • [FJOI2017]矩阵填数 (容斥原理)

    题目传送门
    现在看来熊猫杯的J题原来是个容斥套路题,按照值域排序后根据值域划分方块数,枚举子集容斥计算即可。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int p = 1e9 + 7;
    const int N = 1100;
    
    struct Matrix{
        int x, y, x1, y1, v;
        
        bool check() { return (x <= x1) && (y <= y1); }
        int cal() { return (x1 - x + 1) * (y1 - y + 1); }
        void read() { scanf("%d%d%d%d%d", &x, &y, &x1, &y1, &v); }
    
        bool operator <(const Matrix &ret) { return v < ret.v; }
     
        void operator |(const Matrix &ret){
            x = max(x, ret.x),  y = max(y, ret.y);
            x1 = min(x1, ret.x1),  y1 = min(y1, ret.y1);
        }
    }mat[15];
    
    int h, w, n, m;
    int s[N], u[N], num[N];
    
    int qpow(int x, int k){
        int ans = 1;
        for(; k; k >>= 1){
            if(k & 1)  ans = 1LL * ans * x % p;
            x = 1LL * x * x % p; 
        }
        return ans;
    }
    
    void solve(){
        scanf("%d%d%d%d", &h, &w, &m, &n);
        for(int i = 1; i <= n; ++i)  mat[i].read();
        sort(mat + 1, mat + 1 + n);
        // 求交集
        for(int i = 1, up = 1 << n; i < up; ++i){
            Matrix tt = {1, 1, h, w, 0};
            for(int t = i, j = 1; t; t >>= 1, ++j){
                if(t & 1)  tt | mat[j];
            }
            if(tt.check())  s[i] = tt.cal();  
        }
        // 求并集
        for(int i = 1, up = 1 << n; i < up; ++i){
            for(int t = i; t; t = (t - 1) & i){
                if(num[t] & 1)  u[i] += s[t];
                else  u[i] -= s[t];  
            }
        }
        // 划分值域容斥计算
        // now是目前枚举的集合,pre是之前枚举过的集合
        int now = 0, pre = 0, ans = 1;
        for(int i = 1; i <= n; ++i){
            now |= (1 << (i - 1));
            if(mat[i].v == mat[i + 1].v)  continue;
            int res = u[now | pre] - u[pre];
            int sum = qpow(mat[i].v, res);
            for(int t = now; t; t = (t - 1) & now){
                int tot = u[t | pre] - u[pre];
                int del = 1LL * qpow(mat[i].v - 1, tot) * qpow(mat[i].v, res - tot) % p;
                if(num[t] & 1)  sum = (sum - del + p) % p;
                else  sum = (sum + del) % p; 
            }   
            ans = 1LL * ans * sum % p;
            pre |= now;
            now = 0;
        }
        printf("%d
    ", 1LL * ans * qpow(m, h * w - u[(1 << n) - 1]) % p);
    }
    
    void clr(){
        for(int i = 0; i < N; ++i)  s[i] = u[i] = 0;
    }
    
    int main(){
        int T;
        scanf("%d", &T);
        for(int i = 1; i < N; ++i)  num[i] = num[i >> 1] + (i & 1);
        while(T--){
            solve();
            clr();
        }
    }
    
    你只有十分努力,才能看上去毫不费力。
  • 相关阅读:
    Markdown简介
    主动安全协议-广东标准(粤标)和江苏标准(苏标)的区别及平台开发
    机动车驾驶员计时培训系统平台技术规范
    DevOps 之路
    allinaws
    Dockerfile-For-Python
    Mac 添加vmware fusion nat网卡信息
    AWS 使用S3为Web站点
    AWS ALB实现80端口跳转443端口
    深入理解Service
  • 原文地址:https://www.cnblogs.com/214txdy/p/14205077.html
Copyright © 2011-2022 走看看