zoukankan      html  css  js  c++  java
  • FJOI2017 矩阵填数

    传送门
    这题其实在容斥那一部分还是比较好想的。首先很快的可以发现,矩阵中不同值域的格子会连成一个个不规则区域,而且不同值域的格子互不影响,那么我们可以单独计算每种值域构成的区域的情况,之后用乘法原理乘起来就是答案。

    因为有一些值域可能同时包含多个矩形,所以我们要用容斥,先强制一个矩形不能取max,再两个……这样就可以计算出来了。

    于是乎现在我的一种暴力思路是求出各个不同值域矩形的面积。然后我发现我不会求……

    于是学了一招。我们把满足矩阵限制的情况压成一个二进制数,用(u[i])表示在满足限制i的情况下的格子数。之后对于求每个i的矩形格子数,我们首先暴力求所有矩形的交并且计算答案,在求并的时候只要枚举子集并使用容斥原理就可以计算了。

    计算答案的时候与之类似,按值域从小到大枚举矩形,之后使用容斥原理计算这一部分的答案是多少,所有的都乘起来就好了。中间使用了位运算的方法来快速求出符合当前限制的有多少个格子,之后用快速枚举子集的方法计算容斥。复杂度(O(3^n))

    #include<bits/stdc++.h>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define fr friend inline
    #define y1 poj
    #define mp make_pair
    #define pr pair<int,int>
    #define fi first
    #define sc second
    #define pb push_back
    
    using namespace std;
    typedef long long ll;
    const int M = 10005;
    const ll mod = 1e9+7;
    const double eps = 1e-7;
    
    ll read()
    {
       ll ans = 0,op = 1;char ch = getchar();
       while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
       while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
       return ans * op;
    }
    
    ll T,h,w,m,n,sum,s[2005],size[2005],u[2005],res;
    int ns,ls;
    ll inc(ll a,ll b){return (a+b) % mod;}
    ll mul(ll a,ll b){return a * b % mod;}
    ll qpow(ll a,ll b)
    {
       ll p = 1;
       while(b)
       {
          if(b & 1) p = mul(p,a);
          a = mul(a,a),b >>= 1;
       }
       return p;
    }
    
    struct matrix
    {
       ll x1,x2,y1,y2,v;
       bool empty(){return (x1 > x2) || (y1 > y2);}
       ll cal(){return (x2-x1+1) * (y2-y1+1);}
       void operator &= (const matrix &a){x1 = max(x1,a.x1),x2 = min(x2,a.x2),y1 = max(y1,a.y1),y2 = min(y2,a.y2);}
       bool operator < (const matrix &a){return v < a.v;}
    }r[15],mat;
    
    int main()
    {
       rep(i,1,1<<10) size[i] = size[i>>1] + (i&1);
       T = read();
       while(T--)
       {
          h = read(),w = read(),m = read(),n = read();
          rep(i,1,n) r[i].x1 = read(),r[i].y1 = read(),r[i].x2 = read(),r[i].y2 = read(),r[i].v = read();
          sort(r+1,r+n+1),sum = (1<<n) - 1;
          rep(i,1,sum)//矩形面积交集
          {
    	 bool flag = 1;
    	 mat.x1 = mat.y1 = 1,mat.x2 = h,mat.y2 = w;
    	 for(int p = i,j = 1;p;p >>= 1,j++)
    	 {
    	    if(p & 1) mat &= r[j];
    	    if(mat.empty()) {s[i] = 0,flag = 0;break;}
    	 }
    	 if(flag) s[i] = mat.cal();
          }
          rep(i,1,sum) for(int j = i;j;j = (j-1) & i) (size[j] & 1) ? u[i] += s[j] : u[i] -= s[j];//矩形面积并集
          ns = ls = 0,res = 1;
          rep(i,1,n)
          {
    	 ns |= (1<<(i-1));//表示当前取到的所有限制
    	 if(r[i].v == r[i+1].v) continue;
    	 ll tot = u[ns|ls] - u[ls],st = tot,ret = qpow(r[i].v,tot);//减去之前的限制,只留下现在的
    	 for(int k = ns;k;k = (k-1) & ns)//快速枚举子集用容斥计算
    	 {
    	    tot = u[k|ls] - u[ls];
    	    ll det = mul(qpow(r[i].v-1,tot),qpow(r[i].v,st - tot));
    	    (size[k] & 1) ? ret = inc(ret,mod-det) : ret = inc(ret,det);
    	 }
    	 res = mul(res,ret),ls |= ns,ns = 0;
          }
          printf("%lld
    ",mul(res,qpow(m,h*w-u[sum])));
          rep(i,0,sum) u[i] = 0;
       }
       return 0;
    }
    
    
  • 相关阅读:
    002变量
    001Java输入、eclipse快捷键
    040同步条件event
    kali配置ip,更新源,更新签名
    039条件变量同步(Condition)
    038信号量
    037多线程同步
    配置java环境变量(详细)
    提高你的Python能力:理解单元测试
    电影里的代码之《机械姬》:筛法求质数
  • 原文地址:https://www.cnblogs.com/captain1/p/10457060.html
Copyright © 2011-2022 走看看