• 题解 「一本通 5.4 练习 1」涂抹果酱


    题目传送门

    题目大意

    给出 (n,m,k) ,表示有一个 (n imes m) 的网格,第 (k) 行已经确定了,每个格子只能填 (1,2,3),但是必须满足相邻格子颜色不同,问有多少种合法方案。

    (1le kle nle 10^4,mle 5)

    思路

    因为这道题目并不难,所以这篇博客主要讲如何卡到 ( ext{LOJ rank1})(至少在2020-09-17还是,希望还有线性方法的出现吧,感觉非线性做法已经压到极致了)

    很显然,我们可以设 (dp[i][S]) 表示第 (i) 行状态为 (S) 的方案数。初始显然,转移显然。下面讲优化。

    • 滚动数组

    经实测,可以优化 (20ms) 左右。

    • 预处理

    可以处理出哪些状态合法,已经每个状态可以从哪些状态转移过来。后者可以用 ( ext{vector}) 储存下来。

    • 压缩

    你发现合法的状态最多只有 (3 imes 2^{m-1}le48) 个,你可以先搜索一波,然后预处理的时候只考虑这 (48) 之间的关系就好了。

    此时时间复杂度已经降为了 (Theta((3 imes 2^m)^2n))

    • 矩阵优化

    你发现这个东西可以矩阵优化,显然,时间复杂度降为 (Theta(27 imes 8^m imes log n))


    注意:矩阵乘法的时候先用 ( ext{long long}) 运算,这样可以减少取模次数

    ( exttt{Code})

    #pragma GCC optimize("O3")
    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define ll long long
    #define mod 1000000
    #define MAXN 6
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> void Add (T &a,int b){a = a + b >= mod ? a + b - mod : a + b;}
    
    vector <int> G[50];bool vis;
    int n,m,k,tot,sta,ans,nows,s[5],ind[50],dp[2][50];
    
    void dfs (int x,int las,int sta){
    	if (x == m) return ind[++ tot] = sta,vis |= (sta == nows),void ();
    	for (Int i = 1;i <= 3;++ i) if (i ^ las) dfs (x + 1,i,sta | (1 << x * 2) * i);
    }
    
    ll tmp[50][50];
    
    struct Matrix{
    	int val[50][50];
    	Matrix(){memset (val,0,sizeof (val));}
    	int * operator [] (int key){return val[key];}
    	Matrix operator * (const Matrix &p)const{
    		Matrix New;
    		memset (tmp,0,sizeof (tmp));
    		for (Int i = 0;i <= tot;++ i)
    			for (Int j = 0;j <= tot;++ j)
    				for (Int k = 0;k <= tot;++ k)
    					tmp[i][j] += 1ll * val[i][k] * p.val[k][j];
    		for (Int i = 0;i <= tot;++ i)
    			for (Int j = 0;j <= tot;++ j)
    				New[i][j] = tmp[i][j] % mod;
    		return New; 
    	}
    }A,B,C;
    
    Matrix operator ^ (Matrix a,int b){
    	Matrix res;
    	for (Int i = 0;i <= tot;++ i) res[i][i] = 1;
    	for (;b;b >>= 1,a = a * a) if (b & 1) res = res * a;
    	return res; 
    }
    
    signed main(){
    	read (n,m,k);
    	for (Int i = 0;i < m;++ i) read (s[i]),nows |= ((1 << (i * 2)) * s[i]);
    	dfs (0,0,0);if (!vis) return puts ("0"),0;int bel;
    	for (Int i = 1;i <= tot;++ i){
    		if (ind[i] == nows) bel = i; 
    		for (Int j = i + 1;j <= tot;++ j){
    			int S1 = ind[i],S2 = ind[j];bool flag = 1;
    			for (Int j = 0;j < m;++ j) if ((S1 >> (j * 2) & 3) == (S2 >> (j * 2) & 3)){flag = 0;break;}
    			if (flag) A[i][j] = A[j][i] = 1;
    		}
    		A[i][0] = 1;
    	}
    	B[bel][0] = 1;
    	for (Int i = 1;i <= tot;++ i) B[bel][i] = A[bel][i];
    	C = (A ^ (k - 1)) * B * (A ^ (n - k));
    	for (Int i = 1;i <= tot;++ i) Add (ans,C[i][0]);
    	write (ans),putchar ('
    ');
    	return 0; 
    }
    
  • 相关阅读:
    智能手表如何救人一命?
    人工智能、机器学习和认知计算入门指南
    PO VO BO DTO POJO DAO的解释
    web UI框架推荐
    面向切面编程AOP
    阿里巴巴java开发规范
    如何理解Spring IOC
    HTML5 3D旋转图片相册
    JSON总结笔记
    轮播图---可以动态添加图片,(封装成一个函数)
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13685170.html
Copyright © 2020-2023  润新知