题解 「一本通 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; 
}
原文地址:https://www.cnblogs.com/Dark-Romance/p/13685170.html