• 【HDU】P5471 Count the Grid


    状压dp+容斥

    由于n各集合有(2^n)个交集,因此我们可以把整个矩形划分成许多含有若干矩阵交集的子矩阵。

    就像第一个样例就可以这样划分。

    这样的话,我们就不用讨论许多矩阵相交的情况,问题就会简化很多。

    (mx[i])表示第i个子矩阵内的最大值, (S[i]) 表示第i个子矩阵内含有的元素数量

    然后,我们考虑状压dp。对于一个子矩阵,我们有如下决策:

    1.子矩阵内的最大值小于$mx[i] $,此时方案数为 ((mx[i]-1)^{S[i]})
    由于矩阵是许多矩阵的交集,只要一个矩阵最大值达到了 (mx[i]),那么当前矩阵实际最大值也为 (mx[i]),也是合法的。

    2.子矩阵内的最大值为(mx[i]) ,此时方案数为 (mx[i]^{S[i]}-(mx[i]-1)^{S[i]}) 。由于矩阵是许多矩阵的交集,因此当前取到最大值可能会影响到一些其它矩阵。

    那么,(dp[i][j]) 表示前i个矩阵,取得最大值的矩阵状态为j的方案数

    状态转移:

    [dp[i][j]=dp[i][j]+dp[i-1][j] cdot (mx[i]-1)^{S[i]} ]

    [dp[i][j|can[i]]=dp[i][j|can[i]]+dp[i-1][j]cdot mx[i]^{S[i]}-(mx[i]-1)^{S[i]} ]

    其中(can[i])表示第i个矩阵最大值取到 (mx[i]) 会使得哪些矩阵达到最大值

    而对于划分成许多子矩阵我们可以用容斥预处理一波。

    注意:所有矩阵的并集可能不为整个矩阵,也就是说,这种情况下,有若干个点是可以随便取的(就像样例1),我们最后还要乘以(m^{cnt})((cnt)表示可以随便取的点数量)

    代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int T,h,w,m,n,dp[(1<<10)+5][(1<<10)+5],MM[(1<<10)+5],cas,sum=0;
    const int MOD=1e9+7;
    struct Set{
    	int x1,y1,x2,y2,mx,SS;
    	int S(){
    		return max(x2-x1+1,0LL)*max(y2-y1+1,0LL);
    	}
    }A[10010],B[10010];
    Set operator + (Set X,Set Y){
    	Set Ans;
    	Ans.mx=min(X.mx,Y.mx);
    	Ans.x1=max(X.x1,Y.x1);
    	Ans.y1=max(X.y1,Y.y1);
    	Ans.x2=min(X.x2,Y.x2);
    	Ans.y2=min(X.y2,Y.y2);
    	return Ans;
    }
    int Quick_Pow(int a,int p){
    	int res=1;
    	while(p){
    		if(p&1)res=res*a%MOD;
    		a=a*a%MOD;
    		p>>=1;
    	}
    	return res;
    }
    signed main(){
    	scanf("%lld",&T);
    	while(T--){
    		memset(dp,0,sizeof(dp));
    		memset(A,0,sizeof(A));
    		memset(B,0,sizeof(B));
    		memset(MM,0,sizeof(MM));
    		scanf("%lld %lld %lld %lld",&h,&w,&m,&n);
    		A[0]=Set{1,1,h,w,2e9+7,0};
    		for(int i=1;i<=n;i++){
    			scanf("%lld %lld %lld %lld %lld",&B[(1<<(i-1))].x1,&B[(1<<(i-1))].y1,&B[(1<<(i-1))].x2,&B[(1<<(i-1))].y2,&B[(1<<(i-1))].mx);
    		}
    		for(int i=1;i<(1<<n);i++)A[i]=A[i-(i&-i)]+B[i&-i];
    		for(int i=(1<<n)-1;i>=0;i--){
    			A[i].SS=A[i].S();
    			for(int j=i+1;j<(1<<n);j++){
    				if((j|i)==j)A[i].SS-=A[j].SS;
    			}
    			for(int j=1;j<=n;j++){
    				if((1<<(j-1))&i){
    					if(A[i].mx==A[(1<<(j-1))].mx){
    						MM[i]|=(1<<(j-1));
    					}
    				}
    			}
    		}
    		dp[0][0]=1;
    		for(int i=1;i<(1<<n);i++){
    			for(int j=0;j<(1<<n);j++){
    				dp[i][j]+=dp[i-1][j]*Quick_Pow(A[i].mx-1,A[i].SS)%MOD,dp[i][j]%=MOD;
    				dp[i][j|MM[i]]+=dp[i-1][j]*(Quick_Pow(A[i].mx,A[i].SS)-Quick_Pow(A[i].mx-1,A[i].SS)+MOD)%MOD,dp[i][j|MM[i]]%=MOD;
    			}
    		}
    		sum=h*w;
    		for(int i=1;i<(1<<n);i++)sum-=A[i].SS;
    		printf("Case #%lld: %lld
    ",++cas,dp[(1<<n)-1][(1<<n)-1]*Quick_Pow(m,sum)%MOD);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Fragments (Android官方文档中文版)
    android文件存储的4种方式
    【翻译】C# 使用Image Guid 验证图片类型
    【转载】C# 在线程同步中使用信号量
    【翻译】SQL SERVER 2008 发送DataBase Mail
    【原创】C# Linq to XML
    【转】Web Service身份验证
    【原创】C# HttpWebRequest 发送SOAP XML
    【原创】包含CDATA C#操作XML(无命名空间),添加/删除/编辑节点
    MSSqlServer函数Len()、DataLength()
  • 原文地址:https://www.cnblogs.com/SillyTieT/p/11457530.html
Copyright © 2020-2023  润新知