P1357 花园

算法

我们发现题目中\(m < 5\)很小

所以我们可以使用二进制压缩。

我们用\(1\)来表示\(C\)\(0\)表示\(P\),我们压缩的是当前这个状态的最后\(m\)位的状态 比如后\(m\)位是\(CCPP\)则压缩为\((1100)_2\)这个数

接下来我们讨论一下状态如何转移

首先好像我对于一个状态的转移和其他题解的方法不大相同。
我对于一个状态向其他状态的转移是这样的:

now_0 = (now << 1) & ((1 << m) - 1);
now_1 = (now << 1) & ((1 << m) - 1) + 1;

这个转移可能是更加符合题目的意思吧。
举个栗子:

就如题目中所给的例子 \(m = 2\ k = 1\)

我们就有如下的转移:

\(00\ -> 01\)

\(00\ -> 00\)

\(10\ -> 01\)

\(10\ -> 00\)

\(01\ -> 10\)

我们可以发现从现在这个状态\([i ,i + m]\)\([i + 1,i + m + 1]\)的状态转移相当把\([i,i + m]\) 这个状态的第一个数字挤出去,再在最后一位填上新的数字,我们设\(f[i][j]\)为第\(i\)位向后\(m\)位状态为\(j\)的方案数。

那么我们就知道如果我们枚举\([0,m]\)的状态 则我们的答案是\(f[n + 1][j] \ j\)\(2\)进制下\(1\)的个数小于\(k\)。我们还发现每个\(f[i][j]\)都从\(f[i - 1][j]\)达到,所以我们可以用上滚动数组 这样能够做到\(70pts\)

但我们可是冲着\(100pts\)去的啊 区区\(70pts\)

我们可以预处理出这个一个矩阵,类似于邻接矩阵,将\(i ->j\)这个一个关系,当成一条边存入,这个过程可以使用\(dfs\)。然后我们要做的是转移,就转换成了经典的图上求到达每个点的方案数了,类似于P2886 [USACO07NOV]Cow Relays G这个用矩阵快速幂的题目(建议先做这个题),我们本题也可以使用矩阵快速幂来进行加速。

最后上代码啦

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MOD 1000000007 

using namespace std;

ll n,m,k,fin = 0;

bool vis[(1 << 6) + 1][(1 << 6) + 1];

struct map{
	ll f[(1 << 6) + 1][(1 << 6) + 1]; 
	map(){
		memset(f,0,sizeof(f));
	}
}a,ans;

void dfs(ll now,ll last){
	if(vis[last][now])
	return;
	if(now >= (1 << m))
	return;
	vis[last][now] = 1;
	a.f[last][now] = 1;
	ll z = now;
	now = (now << 1) & ((1 << m) - 1);
	if(__builtin_popcount(now) >= k)
	dfs(now,z);
	else{
		dfs(now + 1,z);
		dfs(now,z);
	}
}

map operator * (const map &x,const map &y){
	map z;
	for(ll i = 0;i <= (1 << m) - 1;i ++)
	for(ll j = 0;j <= (1 << m) - 1;j ++)
	for(ll k = 0;k <= (1 << m) - 1;k ++)	
	z.f[i][j] = (z.f[i][j] + (1ll * x.f[i][k] * y.f[k][j]) % MOD) % MOD;
	return z;
} 
void quick(ll k){
	ans = a;
	k -= 1;
	while(k){
		if(k & 1) ans = ans * a;
		a = a * a;
		k >>= 1;
	}
}
int main(){
	scanf("%lld%lld%lld",&n,&m,&k);
    dfs(0,0);
    quick(n);
	for (int i = 0; i < (1 << m) - 1; ++i) {
		fin = (fin + ans.f[i][i]) % MOD;
	}
    cout<<fin;
} 

posted @ 2020-10-20 22:16  fhq_treap  阅读(103)  评论(0编辑  收藏  举报