• FJOI2017 矩阵填数


    题目

    给定一个 (h imes w) 的矩阵,每个格子中将填入 (1)(m) 中的某个整数。
    一个合法的填数方案须满足 (n) 条限制,每条限制形如“以 ((x_1,y_1)) 为左上角,((x_2,y_2)) 为右下角的子矩阵中,最大值必须为 (v)”。
    求填数方案数,对大质数取模。

    把这 (n) 条限制按照 (v) 从小到大排序。

    这样,就可以对每个 (x) 求出最小限制为 (x) 的区域的答案,最后处理没被限制的区域(这显然是 (m^{S_R})(S_R) 没被限制的区域的面积)。

    答案就是把这些东西全部乘起来。

    接下来考虑对于每个 (x) 求出最小限制为 (x) 的区域的答案。

    (A) 为所有 (v) 值等于 (x) 的限制构成的集合。我们要满足 (A) 中所有限制,并不好算,考虑容斥。

    改为对 (A) 的每个子集 (B),求强制让其不满足的方案数,大概是 ((x-1)^{S_B}x^{S_{A-B}}) ,其中 (S_A) 为集合 (A) 中所有子矩阵的并的面积去掉其中有更小限制的面积。然后加加减减就行。

    发现我们还要求区域面积,当然可以离散化坐标值然后随便搞,但那个细节巨多。考虑更好写的方法:继续容斥。

    我们发现本题中所有的面积都可以转为矩形的交和并。

    发现矩形交是好求的,而并的就等于其子集的交加加减减,然后就求完了。枚举子集的子集是 (O(3^n)) 的。

    每组数据的复杂度为 (O(3^n+2^nnlog(hw)))(log) 来自快速幂。(当然可以 FMT 把 (3^n) 优化掉,优化到 (O(2^nnlog(hw))),但没有必要)。

    #include<cstdio>
    #include<algorithm>
    typedef long long ll;
    const int N=10,M=1e9+7;
    inline int Pow(int a,int m){int s=1;for(;m;m>>=1)m&1?s=(ll)s*a%M:0,a=(ll)a*a%M;return s;}
    int x[N],y[N],xx[N],yy[N],mx[N],t[N],n,m,h,w,cnt[1<<N],ans,tmp;ll cup[1<<N],cap[1<<N];
    bool Cmp(const int&i,const int&j){return mx[i]<mx[j];}
    int main(){
        int a,b,aa,bb,U;
    	for(int I=0;I<(1<<N);I++)cnt[I]=cnt[I>>1]+(I&1);
    	int T;scanf("%d",&T);for(;T--;){
    	scanf("%d%d%d%d",&h,&w,&m,&n);
    	for(int i=0;i<n;i++)scanf("%d%d%d%d%d",x+i,y+i,xx+i,yy+i,mx+i),t[i]=i;
    	std::sort(t,t+n,Cmp);
    	for(int I=0;I<(1<<n);I++){
    	  a=b=0,aa=h,bb=w;
    	  for(int i=0;i<n;i++)if(I&1<<i){
    		a=std::max(a,x[i]);
    		b=std::max(b,y[i]);
    		aa=std::min(aa,xx[i]);
    		bb=std::min(bb,yy[i]);
    	  }
    	  cap[I]=a>aa||b>bb?0:(ll)(aa-a+1)*(bb-b+1);
    	}
    	for(int I=0;I<(1<<n);I++){
    	  cup[I]=0;
    	  for(int J=I;J;J=I&J-1)
    		cup[I]=(cup[I]+cap[J]*(cnt[J]&1?1:-1));
    	}
    	ans=Pow(m,h*w-cup[(1<<n)-1]);
    	U=0;
    	for(int l=0,r=0,I;r<n;r++)if(r+1==n||mx[t[r]]!=mx[t[r+1]]){
    	  I=0;
    	  for(int i=l;i<=r;i++)I|=1<<t[i];
    	  tmp=Pow(mx[t[r]],cup[I|U]-cup[U]);
    	  for(int J=I;J;J=I&J-1)
    		tmp=(tmp+(ll)Pow(mx[t[r]]-1,cup[J|U]-cup[U])*Pow(mx[t[r]],cup[I|U]-cup[J|U])%M*(cnt[J]&1?-1:1)+M)%M;
    	  ans=(ll)ans*tmp%M;
    	  U|=I,l=r+1;
    	}
    	printf("%d
    ",ans);
    	}return 0;
    }
    
  • 相关阅读:
    filter in the new axis?
    项目 ".wdproj "所需的应用程序未安装。确保已安装项目类型(.wdproj)的应用程序
    firefox的webmail notifier网易邮箱设置
    phpmyadmin导出数据中文乱码问题解决
    Eclipse快捷键大全(转载)
    Android Error: Unable to open class file R.java
    将 SQL Server Express 版用于 ASP.NET (Visual Studio)
    MySql常用命令
    Godaddy Google Adwords 促销代码使用
    HTTP 错误 500.22 Internal Server Error—IIS7 Asp.net2.0 网站运行失败解决办法
  • 原文地址:https://www.cnblogs.com/Camp-Nou/p/12334197.html
Copyright © 2020-2023  润新知