题目大意

  小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 花园 状态压缩 矩阵快速幂的更多相关文章

  1. 洛谷P1357 花园(状态压缩 + 矩阵快速幂加速递推)

    题目链接:传送门 题目: 题目描述 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(<=N<=^).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻 ...

  2. P1357 花园 状压 矩阵快速幂

    题意 小L有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为1~N(2<=N<=10^15).他的环形花园每天都会换一个新花样,但他的花园都不外乎一个规则,任意相邻M(2<=M& ...

  3. hihocoder第42周 3*N骨牌覆盖(状态dp+矩阵快速幂)

    http://hihocoder.com/contest/hiho42/problem/1 给定一个n,问我们3*n的矩阵有多少种覆盖的方法 第41周做的骨牌覆盖是2*n的,状态转移方程是dp[i] ...

  4. hihocoder第42周 k*N骨牌覆盖(状态dp+矩阵快速幂)

    上周的3*N的骨牌,因为状态只有8中,所以我们可以手算出状态转移的矩阵 但是这周是k*N,状态矩阵不好手算,都是我们改成用程序自动生成一个状态转移的矩阵就行了,然后用这个矩阵进行快速幂即可 枚举枚举上 ...

  5. 【BZOJ2004】公交线路(动态规划,状态压缩,矩阵快速幂)

    [BZOJ2004]公交线路(动态规划,状态压缩,矩阵快速幂) 题面 BZOJ 题解 看到\(k,p\)这么小 不难想到状态压缩 看到\(n\)这么大,不难想到矩阵快速幂 那么,我们来考虑朴素的\(d ...

  6. [luogu1357] 花园 [dp+矩阵快速幂]

    题面: 传送门 思路: 把P形花圃记录为0,C形记录为1,那么一段花圃就可以状态压缩成一个整数 那么,我们可以有这样的状压dp: dp[i][S]表示前i个花圃,最后m个的状态为S的情况 如果这是一条 ...

  7. P1357 花园 (矩阵快速幂+ DP)

    题意:一个只含字母C和P的环形串 求长度为n且每m个连续字符不含有超过k个C的方案数 m <= 5  n <= 1e15 题解:用一个m位二进制表示状态 转移很好想 但是这个题是用矩阵快速 ...

  8. bzoj2004 矩阵快速幂优化状压dp

    https://www.lydsy.com/JudgeOnline/problem.php?id=2004 以前只会状压dp和矩阵快速幂dp,没想到一道题还能组合起来一起用,算法竞赛真是奥妙重重 小Z ...

  9. ZZNU 2182 矩阵dp (矩阵快速幂+递推式 || 杜教BM)

    题目链接:http://47.93.249.116/problem.php?id=2182 题目描述 河神喜欢吃零食,有三种最喜欢的零食,鱼干,猪肉脯,巧克力.他每小时会选择一种吃一包. 不幸的是,医 ...

随机推荐

  1. Leetcode0143--Reorder List 链表重排

    [转载请注明]https://www.cnblogs.com/igoslly/p/9351564.html 具体的图示可查看 链接 代码一 /** * Definition for singly-li ...

  2. node 第三方包学习

    时间格式化 moment var moment = require('moment'); moment().format();

  3. html5——多媒体(一)

    <audio> 1.autoplay 自动播放 2.controls 是否显不默认播放控件 3.loop 循环播放 4.preload 预加载 同时设置autoplay时些属性失效 5.由 ...

  4. JavaScript面试题链接汇总

    最新JavaScript笔试题(含答案) - 爱思资源网 前端工程师面试问题列表 - 爱思资源网 腾讯最新前端面试题记录分享 - 爱思资源网 优酷前端JS部分面试题 - 爱思资源网 百度校园招聘web ...

  5. [文章转载]-Java后端,应该日常翻看的中文技术网站 -江南白衣

    Java后端,应该日常翻看的中文技术网站 1.内容生产者 InfoQ 中文技术第一站,佩服霍老板,真金白银地为中国程序员们生产内容. ImportNew 专门面向Java的内容生产者兼聚合者,偶然也有 ...

  6. Codeforces_733C

    C. Epidemic in Monstropolis time limit per test 1 second memory limit per test 256 megabytes input s ...

  7. 郁闷的出纳员 题解(Splay)

    题面 看似是要区间修改,然而实际上只需要维护底线和工资的相对大小关系, 瞬间变水 用delta记录对工资的加减,那么添加节点时点权应-delta,输出时+delta 几种操作中减少工资较麻烦: 1.d ...

  8. CAD创建一个新的图形文件

    static void linea(void) { AcDbDatabase *pDb = new AcDbDatabase(true, false); AcGePoint3d pickPoint; ...

  9. Swift 3到5.1新特性整理

    本文转载自:https://hicc.me/whats-new-in-swift-3-to-5-1/,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有. Hipo 2.0 重写从 Swif ...

  10. mapbox-gl 使用ArcGISServer 发布的栅格切片

    最近使用mapbox 进行数据化展现.刚好用到了超图平台在去三维系统,顺带就用超图平台发布了栅格切片,用来做底图,但是超图平台是试用的许可,栅格切片有SuperMap 的水印,实在不雅观. 在网上搜索 ...