zoukankan      html  css  js  c++  java
  • HDU 4332 Contest 4

    顶好的一道题。其实,是POJ 2411的升级版。但POJ 2411我用的插头DP来做,一时没想到那道题怎么用状态DP,于是回头看POJ 2411那一道的状态DP,其实也很简单,就是每一行都设一个状态,用位来表示,如果上一行为0,则当前行必定是要竖着放的。填1.否则,当前行的位置可以横放填两个格子为1,也可以不放,为0.于是,看上一行的状态能转移到哪些状态,就可以了。

    这一道也是一样的想做法,DFS看开始时有哪些状态,记在一个一维矩阵里。因为有一些状态最开始是达不到的,如奇数个1,或者一些不连续1的状态。然后求转移矩阵(这个地方想了很久才想到,因为要做很多重复的工作,所以想到用矩阵)。求矩阵时,也用DFS就可以了。

    此处在矩阵相乘时有一个小优化,因为转移矩阵中含0较多,所以把中间变量K提到第一个循环。当含有0时就终止。因为这个地方由TLE,优化到了8000MS,也是满足了。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define LL __int64
    #define mod 1000000007
    using namespace std;
    
    struct Matrix{
    	LL ans[130][130];
    };
    Matrix pp[31];
    
    LL bgn[130];
    LL res[130];
    int only;
    int number[260];
    Matrix transfer;
    Matrix per;
    bool ok(int s){
    	int c=0;
    	for(int i=0;i<8;i++)
    	if(s&(1<<i)) c++;
    	if(c%2==0) return true;
    	return false;
    }
    
    Matrix operator *(Matrix a,Matrix b){
    	Matrix c;
    	for(int i=0;i<only;i++)
    	for(int j=0;j<only;j++)
    	c.ans[i][j]=0;
    	for(int k=0;k<only;k++)    //把k提到这里来就过了。。。哈哈,这也是一种优化啊,因为矩阵中0较多,避免了不必要的计算。 
    	for(int i=0;i<only;i++){
    		if(a.ans[i][k]==0) continue;
    		for(int j=0;j<only;j++){
    			c.ans[i][j]=(c.ans[i][j]+(a.ans[i][k]*b.ans[k][j])%mod)%mod;
    		}
    	}
    	return c;
    }
    
    void find_bgn(int state,int pos){
    	if(pos>=8) {
    		bgn[number[state]]++;
    		return ;
    	}
    	int tmp=state;
    	int i=pos;
    	if((state&(1<<i))==0&&(state&(1<<((i+1)%8)))==0){
    		tmp=state|(1<<i)|(1<<((i+1)%8));
    		find_bgn(tmp,i+2);
    	}
    	find_bgn(state,i+1);
    }
    
    void dfs(int pre,int state,int pos){
    	if(pos>=8) {
    		transfer.ans[number[pre]][number[state]]++;
    		return ;
    	}
    	int tmp=state;
    	int i=pos;
    	if((state&(1<<i))==0&&(state&(1<<((i+1)%8)))==0){
    		tmp=state|(1<<i)|(1<<((i+1)%8));
    		dfs(pre,tmp,i+2);
    	}
    	dfs(pre,state,i+1);
    }
    
    /*
    LL can(int a,int b)
    {
        int st,i,j;
        bool end=false;
        if(a==0)return b==255? 1LL:0;
        for(i=0;i<8;i++)
        {
            j=(i+7)%8;
            if((a&(1<<i))&&(a&(1<<j))==0)
            {
                st=i;
                break;
            }
        }
        for(i=st;i!=st||end==false;i=(i+1)%8)
        {
            end=true;
            j=(i+1)%8;
            if(0==(a&(1<<i)))
            {
                if(0==(b&(1<<i)))return 0;
            }
            else
            {
                if((a&(1<<j))&&(b&(1<<i))&&(b&(1<<j)))i++;
                else if((b&(1<<i))==0)continue;
                else return 0;
            }
        }
        return 1LL;
    }
    */
    void initial(){
    	only=0;
    	memset(number,-1,sizeof(number));
    	memset(transfer.ans,0,sizeof(transfer.ans));
    	for(int i=0;i<(1<<8);i++)
    	if(ok(i)) number[i]=only++;
    	
    	for(int i=0;i<only;i++)
    	for(int j=0;j<only;j++)
    	if(i==j) per.ans[i][i]=1;
    	else per.ans[i][j]=0;
    	
    	memset(bgn,0,sizeof(bgn));
    	find_bgn(0,0);
    	
    	for(int i=0;i<(1<<8);i++){
    		if(number[i]!=-1){
    			dfs(i,255-i,0);
    		}
    	}
    /*
      for(int i=0;i<1<<8;i++)
           for(int j=i+1;j<1<<8;j++)
           if(number[i]!=-1&&number[j]!=-1)
               transfer.ans[number[j]][number[i]]=transfer.ans[number[i]][number[j]]=can(i,j);
           transfer.ans[only-1][only-1]=2;	
       */    
    	for(int i=1;i<31;i++){
    		if(i==1)
    		pp[i]=transfer;
    		else
    		pp[i]=pp[i-1]*pp[i-1];
    	}
    }
    
    LL pow(int k){
    	Matrix ans=per,ats=transfer;
    	int c=1;
    	while(k){
    		if(k&1) ans=ans*pp[c];
    		k>>=1;
    		c++;
    	}
    	LL tmp=0;
    	for(int j=0;j<only;j++)
    	tmp=(tmp+(bgn[j]*ans.ans[j][only-1])%mod)%mod;
    	return tmp;
    }
    
    int main(){
    	initial();
    	int n,T,kase=0;
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d",&n);
    		LL resul=pow(n-1);
    		printf("Case %d: %I64d
    ",++kase,resul);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    UVA12125 March of the Penguins (最大流+拆点)
    UVA 1317 Concert Hall Scheduling(最小费用最大流)
    UVA10249 The Grand Dinner(最大流)
    UVA1349 Optimal Bus Route Design(KM最佳完美匹配)
    UVA1212 Duopoly(最大流最小割)
    UVA1395 Slim Span(kruskal)
    UVA1045 The Great Wall Game(二分图最佳匹配)
    UVA12168 Cat vs. Dog( 二分图最大独立集)
    hdu3488Tour(KM最佳完美匹配)
    UVA1345 Jamie's Contact Groups(最大流+二分)
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4114924.html
Copyright © 2011-2022 走看看