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 题目描述 河神喜欢吃零食,有三种最喜欢的零食,鱼干,猪肉脯,巧克力.他每小时会选择一种吃一包. 不幸的是,医 ...
随机推荐
- Scala-基础-变量与常量
import junit.framework.TestCase import org.junit.Test //变量 //var 代表变量 //val 代表常量 //关键字 class,extends ...
- LinearLayout中间布局填充出现的问题
线性布局如何中间填充,会挤掉他下面的布局,所以中间填充使用layout_weight属性.
- 02--Java Socket编程--IO方式
一.基础知识 1. TCP状态转换知识,可参考: http://www.cnblogs.com/qlee/archive/2011/07/12/2104089.html 2. 数据传输 3. TCP/ ...
- 7-9 旅游规划 (25 分)(Dijkstra算法)
题意: 思路:单源最短路问题,Dijkstra算法搞定就可以了,因为要找出最便宜的最短路,所以需要在更新最短距离的时候加一个条件(即当最短距离相等的时候,如果该路径的花费更小,就更新最小花费)就可 ...
- RabbitMQ在Ubuntu上的环境搭建
1.修改/etc/apt/sources.list文件 A:命令:vi /etc/apt/sources.list B:在最后一行加上:deb http://www.rabbitmq.com/debi ...
- MySQL数据库操作(一)
一.数据操作 1.显示数据库 show databases; 2.创建数据库 #utf- create database 数据库名称 default charset utf8 collate utf8 ...
- 在Docker上构建mysql容器
1.查看docker上的镜像是否有 mysql,如果没有下载则列表中没有 [root@holly holly]# docker images; 如果没有只会看到如下结构 REPOSITORY TA ...
- VNC Server Installation on CentOS 6.5
In my case I have a fresh installed CentOS6.5 Server on which I will be installing the VNC-server so ...
- sicily 10330. Cutting Sausages
#include<stdio.h> int main() { int n,m,j,k; while(scanf("%d%d",&n,&m)! ...
- 用sqlldr导入csv文件
1.新建文件test.ctl,内容如下 load dataCHARACTERSET 'UTF16' \*指定编码格式,很重要*\ infile 'vodall.csv' append into tab ...