luogu1357 花园 状态压缩 矩阵快速幂
题目大意
小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(2<=N<=10^15)。他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻M(2<=M<=5,M<=N)个花圃中有不超过K(1<=K<M)个C形的花圃,其余花圃均为P形的花圃。请帮小L求出符合规则的花园种数Mod 1000000007。
题解
状态的设计
我们先不考虑环。我对状态的设计是f(i, j, k),i是以第i位起始,j是区间[i, i+m]中最后一个C的位置-i的值,k是[i, i+m]中C的数量,f是排列的种数。后来我认为j也不需要,f(i, k)就行了。但是此方法一个k无法表示出具体的排布状态,这是错误的。
我们看到M<=5,很容易想到用状态压缩来表示具体的状态。所以我们设计出f(i, S),i是位置,S是[i, i+M]中C的排布状态,f是排列的个数。递推式f(i + 1, S >> 1) += f(i, S), f(i + 1, (S >> 1) | (1 << M - 1) += f(i, S),其中涉及到的所有集合内元素个数都不超过K。
环的处理
我当时想到将长度为n的序列尾部再加一个长度为m的序列,从左往右递推,最后输出的结果便是sum{f(n, S)},S满足元素个数<=K,但考虑到这样会导致结尾m个花的排列状态和开头m个花的排列状态不一致而导致错误。于是我就卡住了。
正确的解决办法是枚举开头[1, m]的花的状态S,每次将其固定住,这样DP推导出的DP(n, S)都是由[m + 1, n + m]处花合法的排列得出的了。
矩阵快速幂优化
我们看到对于每一个状态S0,无论i是多少,可以使f(i, S0)去+=的出处f(i+1, S0')都是固定的。所以我们建立一个矩阵A,A(S1, S2)=[对任意i, f(i + 1, S2)需要+=f(i, S1)]。[]内判断为真即1,否则为0。这样,对于每一个开头[1, m]的花的状态S0,建立一个向量B,其中只有S0那一位的项为1(排列方式由S0知道肯定为1),最终的结果便是B*A^N。最后求和即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace std; #define ll long long
const int MAX_M = 7;
const ll P = 1000000007;
ll N, M, K; struct Matrix
{
private:
int TotRow, TotCol; public:
ll A[1 << MAX_M][1 << MAX_M]; void Clear()
{
memset(A, 0, sizeof(A));
} Matrix(int totRow, int totCol) :TotRow(totRow), TotCol(totCol) { Clear(); } Matrix operator * (const Matrix& a) const
{
assert(TotCol == a.TotRow);
Matrix ans(TotRow, a.TotCol);
for (int row = 0; row < TotRow; row++)
for (int col = 0; col < a.TotCol; col++)
for (int k = 0; k < TotCol; k++)
ans.A[row][col] = (ans.A[row][col] + (A[row][k] * a.A[k][col] % P)) % P;
return ans;
} Matrix Power(ll n)
{
Matrix ans(TotRow, TotCol);
for (int i = 0; i < TotRow; i++)
ans.A[i][i] = 1;
Matrix a = *this;
while (n)
{
if (n & 1)
ans = ans * a;
a = a * a;
n >>= 1;
}
return ans;
}
}; int main()
{
scanf("%lld%lld%lld", &N, &M, &K); static bool Exist[1 << MAX_M];
for (int S = 0; S < (1 << M); S++)
{
int cnt = 0;
for (int i = 0; i < M; i++)
cnt += (S & (1 << i)) > 0;
Exist[S] = cnt <= K;
} static Matrix g(1 << M, 1 << M);
for (int S = 0; S < (1 << M); S++)
{
if (Exist[S])
{
g.A[S][S >> 1] = 1;
if (Exist[(S >> 1) | (1 << M - 1)])
g.A[S][(S >> 1) | (1 << M - 1)] = 1;
}
} static Matrix powed = g.Power(N), start(1, 1 << M);
ll ans = 0;
for (int S = 0; S < (1 << M); S++)
{
if (Exist[S])
{
start.Clear();
start.A[0][S] = 1;
ans = (ans + (start * powed).A[0][S]) % P;
}
}
printf("%lld\n", ans);
}
luogu1357 花园 状态压缩 矩阵快速幂的更多相关文章
- 洛谷P1357 花园(状态压缩 + 矩阵快速幂加速递推)
题目链接:传送门 题目: 题目描述 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(<=N<=^).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻 ...
- P1357 花园 状压 矩阵快速幂
题意 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(2<=N<=10^15).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻M(2<=M& ...
- hihocoder第42周 3*N骨牌覆盖(状态dp+矩阵快速幂)
http://hihocoder.com/contest/hiho42/problem/1 给定一个n,问我们3*n的矩阵有多少种覆盖的方法 第41周做的骨牌覆盖是2*n的,状态转移方程是dp[i] ...
- hihocoder第42周 k*N骨牌覆盖(状态dp+矩阵快速幂)
上周的3*N的骨牌,因为状态只有8中,所以我们可以手算出状态转移的矩阵 但是这周是k*N,状态矩阵不好手算,都是我们改成用程序自动生成一个状态转移的矩阵就行了,然后用这个矩阵进行快速幂即可 枚举枚举上 ...
- 【BZOJ2004】公交线路(动态规划,状态压缩,矩阵快速幂)
[BZOJ2004]公交线路(动态规划,状态压缩,矩阵快速幂) 题面 BZOJ 题解 看到\(k,p\)这么小 不难想到状态压缩 看到\(n\)这么大,不难想到矩阵快速幂 那么,我们来考虑朴素的\(d ...
- [luogu1357] 花园 [dp+矩阵快速幂]
题面: 传送门 思路: 把P形花圃记录为0,C形记录为1,那么一段花圃就可以状态压缩成一个整数 那么,我们可以有这样的状压dp: dp[i][S]表示前i个花圃,最后m个的状态为S的情况 如果这是一条 ...
- P1357 花园 (矩阵快速幂+ DP)
题意:一个只含字母C和P的环形串 求长度为n且每m个连续字符不含有超过k个C的方案数 m <= 5 n <= 1e15 题解:用一个m位二进制表示状态 转移很好想 但是这个题是用矩阵快速 ...
- bzoj2004 矩阵快速幂优化状压dp
https://www.lydsy.com/JudgeOnline/problem.php?id=2004 以前只会状压dp和矩阵快速幂dp,没想到一道题还能组合起来一起用,算法竞赛真是奥妙重重 小Z ...
- ZZNU 2182 矩阵dp (矩阵快速幂+递推式 || 杜教BM)
题目链接:http://47.93.249.116/problem.php?id=2182 题目描述 河神喜欢吃零食,有三种最喜欢的零食,鱼干,猪肉脯,巧克力.他每小时会选择一种吃一包. 不幸的是,医 ...
随机推荐
- PHP开发之旅-验证码功能实现
验证码这样的功能可以说是无处不在了,接下来使用php来实现验证码这样的功能,这里我是将验证码实现抽取到一个类中独立开来,那么后面如果再使用到验证码功能,直接引入该类文件并创建该类的实例,就可以使用验证 ...
- [Java]Java分层概念
service是业务层 action层即作为控制器 DAO (Data Access Object) 数据访问 1.JAVA中Action层, Service层 ,modle层 和 Dao层的功能 ...
- html5——文本阴影
基本结构 text-shadow: 30px 23px 31px #;/* 文字阴影: 水平位移 垂直位移 模糊程度 阴影颜色*/ 凹凸文字 <!DOCTYPE html> <htm ...
- JS——高级各行换色
1.获取tbody下的子元素 2.注册鼠标覆盖事件时存储当时的背景颜色,注册鼠标离开事件时把存储的颜色赋值注册事件对象 <!DOCTYPE html> <html> <h ...
- windows phone 8 使用页面传对象的方式 实现页面间的多值传递
在做windows phone 开发的时候,会经常碰到页面间之间的跳转和传递数据,如果传递的值不多,只有两三个,我们通常使用NavigationService.Navigate(new Uri(&qu ...
- 【sqli-labs】 less60 GET -Challenge -Double Query -5 queries allowed -Variation3 (GET型 挑战 双查询 只允许5次查询 变化3)
http://192.168.136.128/sqli-labs-master/Less-60/?id=1")%23 http://192.168.136.128/sqli-labs-mas ...
- VUE路由history模式坑记--NGINX
因微信分享和自动登录需要,对于URL中存在'#'的地址,处理起来比较坑(需要手动写一些代码来处理).还有可能会有一些隐藏的问题没被发现. 如果VUE能像其他(JSP/PHP)系统的路径一样,就不存在这 ...
- CAD通过扩展记录实体向数据库读写用户自定义的全局数据(com接口VB语言)
VB代码实现如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ...
- 怎么选择最适合自己的Linux培训机构?
Linux培训已经成为入门Linux的一个重要途径,它的优势在于学习知识的系统性.快速性和实用性.Linux培训毕业的学员大多数拥有较强的实战动手能力,能够较快上手,更符合企业需求. 不过,大部分同学 ...
- 踪电子表格中的单元格(Spreadsheet Tracking, ACM/ICPC World Finals 1997, UVa512)
有一个r行c列(1≤r,c≤50)的电子表格,行从上到下编号为1-r,列从左到右编号为1 -c.如图4-2(a)所示,如果先删除第1.5行,然后删除第3, 6, 7, 9列,结果如图4-2(b) 所示 ...