zoukankan      html  css  js  c++  java
  • UVA 11741 Ignore the Blocks

    https://vjudge.net/problem/UVA-11741

    题目

    给一个$n$行$m$列的棋盘,上面有一些坏格子(最多100个),剩下的都是好格子,你有充足的$1 imes2$骨牌,问把所有好格子都不重不漏地覆盖同时不能覆盖坏格子的方法有多少个,$1leqslant nleqslant 4, 1leqslant mleqslant 100000000$,输出对10000007取模后的结果。

    题解

    第一次我直接轮廓线dp到末尾,然后就TLE了……

    因为坏格子比较少,行数也很少,因此把行压成一个状态,计算两行状态之间的转移,得到一个矩阵,然后就可以通过矩阵幂计算了……

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<cctype>
    #define REP(i,a,b) for(register unsigned i=(a); i<(b); i++)
    #define REPE(i,a,b) for(register unsigned i=(a); i<=(b); i++)
    #define PERE(i,a,b) for(register unsigned i=(a); i>=(b); i--)
    using namespace std;
    typedef long long ll;
    struct node {
    	int a, b;
    	bool operator<(const node&r) const {
    		return b<r.b;
    	}
    };
    #define MAXN 107
    #define MO 10000007
    node bdcol[MAXN];//记录坏格子
    int dp[2][16];//计算转移用的
    int mtx[5][16][16];//转移矩阵
    int ones[5][16][16];//单位矩阵
    inline void db() {
    	memset(ones,0,sizeof(ones));
    	REP(r,1,5) {
    		unsigned msk=1<<r, m=msk>>1;
    		REP(i,0,msk) {
    			ones[r][i][i]=1;
    		}
    		REP(f,0,msk) {
    			memset(dp[0],0,sizeof(dp[0]));
    			dp[0][f]=1;
    			int now=0;
    			REP(i,0,r) {
    				now^=1; memset(dp[now],0,sizeof(dp[now]));
    				REP(k,0,msk) {
    					if(k&1) dp[now][k>>1]+=dp[now^1][k];
    					if(!(k&1)) dp[now][(k>>1)|m]+=dp[now^1][k];
    					if(i && (k&1) && !(k&m)) dp[now][((k|m)>>1)|m]+=dp[now^1][k];
    				}
    			}
    			REP(t,0,msk) {
    				mtx[r][f][t]=dp[now][t];
    			}
    		}
    	}
    }
    int r,c,n;
    unsigned msk, m;
    inline void mul(const int a[16][16], const int b[16][16], int ret[16][16]) { //矩阵乘法
    	int ans[16][16];
    	REP(i,0,msk) {
    		REP(j,0,msk) {
    			ans[i][j]=0;
    			REP(k,0,msk) {
    				ans[i][j]=(ans[i][j]+((ll)a[i][k]*b[k][j]))%MO;
    			}
    		}
    	}
    	memcpy(ret,ans,sizeof(ans));
    }
    inline void qpow(const int a[16][16], int y, int ret[16][16]) { //矩阵幂
    	int ans[16][16];
    	int x[16][16];
    	memcpy(x,a,sizeof(x));
    	memcpy(ans,ones[r],sizeof(ans));
    	for(;y;y>>=1) {
    		if(y&1) mul(ans,x,ans);
    		mul(x,x,x);
    	}
    	memcpy(ret,ans,sizeof(ans));
    }
    int A[16][16];
    int B[16][16];
    int main() {
    	int kase=1;
    	db();
    	while(~scanf("%d%d%d", &r, &c, &n) && r) {
    		msk = 1u<<r; m=msk>>1;
    		REP(i,0,n) {
    			scanf("%d%d", &bdcol[i].a, &bdcol[i].b);
    		}
    		REP(i,0,r) {
    			bdcol[n].a=i, bdcol[n].b=c;
    			n++;
    		}
    		sort(bdcol,bdcol+n);
    		int now=0, from=-1;//当前坏格子编号和列
    		memcpy(A,ones[r],sizeof(A));
    		int i=0;
    		while(i<n) {
    			now=i;
    			unsigned k=0;
    			while(i<n && bdcol[i].b==bdcol[now].b) {k|=1<<bdcol[i].a; i++;}
    			qpow(mtx[r], bdcol[now].b-from, B); //B=F^{...}
    			mul(A,B,A);
    			memset(B,0,sizeof(B));
    			REP(i,0,msk) REP(j,0,msk) if(!(j&k)) {
    				B[i][j|k]+=A[i][j];
    			}
    			memcpy(A,B,sizeof(A));
    			from = bdcol[now].b;
    		}
    		
    		printf("Case %d: %d
    ", kase, A[msk-1][msk-1]);//从-1排满到最后一排满
    		kase++;
    	}
    	return 0;
    }
    
  • 相关阅读:
    【LeetCode每日一题】2020.6.28 209. 长度最小的子数组
    【《你不知道的JS(中卷①)》】三、原生函数
    【《你不知道的JS(中卷①)》】二、值
    【《你不知道的JS(中卷①)》】一、类型
    【LeetCode每日一题】2020.6.26 面试题 02.01. 移除重复节点
    【LeetCode周赛】第194场周赛
    【LeetCode每日一题】2020.6.25 139. 单词拆分
    ios网络编程(HTTP socket)
    objective c 代码块blocks完整总结二
    objective c 代码块blocks完整总结一
  • 原文地址:https://www.cnblogs.com/sahdsg/p/12328067.html
Copyright © 2011-2022 走看看