【简•解】花园

【题目描述】

传送门

\(L\)有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为\(1\)~\(N(2\le N\le 10^{15})\)。他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻\(M(2\le M\le 5,M\le N)\)个花圃中有不超过\(K(1\le K<M)\)\(C\)形的花圃,其余花圃均为\(P\)形的花圃。

求合法方案数,对模烂的数\(1e9+7\)取模。

【分析】

看到\(M\)这么小,考虑到状压。

但看到\(N\)这么大,那就快速幂吧,此题完。

【Code】

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define ll long long
#define debug() puts("FBI WARNING!")
using namespace std;
const int P = 19260817;
const int MOD = 1000000007;
const int MAX = 300000 + 5; 
const int M = 5;
inline ll read(){
	ll f = 1, x = 0; char ch;
	do { ch = getchar(); if (ch == '-') f = -1; } while (ch < '0' || ch > '9');
	do {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); } while (ch >= '0' && ch <= '9'); 
	return f * x;
}

struct TOOL {
	#define Hanabi ll
	inline Hanabi max(Hanabi a, Hanabi b) { return a < b ? b : a; }
	inline Hanabi min(Hanabi a, Hanabi b) { return a < b ? a : b; }
	inline Hanabi abs(Hanabi a) { return a < 0 ? a : a; }
}t;

int m, K, jd[1 << M], limit, cover;
ll n, f[1 << M], vis[1 << M][1 << M], ans;

inline void mul() {
	ll c[1 << M];
	memset(c, 0, sizeof c);
	for (int j = 0;j < limit; ++j) {
		for (int k = 0;k < limit; ++k) {
			c[j] = (c[j] + f[k] * vis[k][j]) % MOD;
		}
	}
	memmove(f, c, sizeof c);
}

inline void mulself() {
	ll c[1 << M][1 << M];
	memset(c, 0, sizeof c);
	for (int i = 0;i < limit; ++i) {
		for (int j = 0;j < limit; ++j) {
			for (int k = 0;k < limit; ++k) {
				c[i][j] = (c[i][j] + vis[i][k] * vis[k][j]) % MOD;
			}
		}
	}
	memmove(vis, c, sizeof c);
}

int main(){
	n = read(), m = read(), K = read();
	limit = 1 << m;
	cover = (1 << (m - 1)) - 1;
	for (int i = 0;i < limit; ++i) {
		int cnt = 0;
		for (int j = 0;j < m; ++j) {
			if (i & (1 << j)) ++cnt;
		}
		if (cnt <= K) jd[i] = 1;
	}
	
	for (int i = 0;i < limit; ++i) {
		if (jd[i] == 0) continue;
		memset(f, 0, sizeof f);
		f[i] = 1;
		memset(vis, 0, sizeof vis);
		for (int j = 0;j < limit; ++j) {
			if (jd[j] && jd[(j & cover) << 1]) vis[j][(j & cover) << 1] = 1;
			if (jd[j] && jd[((j & cover) << 1) | 1]) vis[j][((j & cover) << 1) | 1] = 1;			
		}
		ll x = n;
		while (x) {
			if (x & 1) mul();
			mulself();
			x >>= 1;
		}
		ans = (ans + f[i]) % MOD;
	}
	printf("%lld", ans);
	return 0;
}
posted @ 2019-08-28 21:25  SilentEAG  阅读(222)  评论(0编辑  收藏  举报