\(\color{#0066ff}{题解 }\)

可以发现, 数据范围中的n特别小,容易想到状压

可以想到类似于状压DP的思路,按列进行转移

那么应该有3维,\(f[i][j][k]\)代表到第i列,j的每一位表示这一行有多少连续的男生,k表示当前有多少列全是男生,的方案数

看到m的范围,我们肯定是要找一个\(O(logm)\)的东西加速转移,自然是矩阵加速

然后我们来看看有多少个状态,看看是否可行

j有\(p^n\)个,k有q个(用矩阵转移第一维自然不需要)

那么状态数依然达到了一个\(p^n*q=3^8*3=19683\)

这东西要是\(O(n^3)\)去转移绝对T到飞起,而且空间也是开不下

所以我们考虑减少状态的数量

发现,我们并不需要知道每一行当前有多少个连续的男生,我们只需要知道有多少行的连续的男生是\(0,1\dots p-1\)个

这相当于把一个数n拆分成p个数的和

这样的状态数绝对是少得多了,就可以矩阵加速了

我们可以通过dfs预处理出所有的状态(状态数极限$\le$200)

然后为了推出转移矩阵,我们需要考虑一个状态对另一个状态的贡献,直接\(n^2\)枚举即可

假设我们现在考虑\(x\to y\)的贡献

设\(x_0, x_1, x_2,xx\)表示状态x中,有连续0个男生的行的数量,有连续1个男生的行的数量,有连续2个男生的行的数量,有多少列全是男生,这个已经dfs预处理过,y同理

如果\(xx + 1 == yy\)

那就说明当前这一列必须全是男生,于是\(x_0\)要全给\(y_1\),\(x_1\)要全给\(y_2\),而且\(x_2\)必须为0,这样才有1的贡献

然后考虑不全为1的

我们肯定是放女生或男生,那么拿\(x_1\)来说,如果一些行放女生,那么这些行就要转移到\(y_0\),如果放男生,就要转移到\(y_2\),那么显然组合一下,方案就是\(C_{x_1}^{x_1-y_2}\),\(x_0\)同理

然后构造完转移矩阵,加速递推即可

#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int mod = 1e9 + 7;
LL n, m, p, q, len;
struct Matrix {
LL ju[222][222];
Matrix() { memset(ju, 0, sizeof ju); }
void e() {
memset(ju, 0, sizeof ju);
for(int i = 1; i <= len; i++) ju[i][i] = 1;
}
friend Matrix operator * (const Matrix &a, const Matrix &b) {
Matrix c;
for(int i = 1; i <= len; i++)
for(int j = 1; j <= len; j++)
for(int k = 1; k <= len; k++)
(c.ju[i][j] += a.ju[i][k] * b.ju[k][j] % mod) %= mod;
return c;
}
Matrix ksm(LL y) {
Matrix x = *this, re;
re.e();
while(y) {
if(y & 1) re = re * x;
x = x * x;
y >>= 1;
}
return re;
}
}beg, A;
LL fac[22], inv[22];
int ls[22];
struct node {
int st[3], num;
node(int a = 0, int b = 0, int c = 0, int d = 0): num(d) {
st[0] = a, st[1] = b, st[2] = c;
}
}st[105050];
LL ksm(LL x, LL y) {
LL re = 1LL;
while(y) {
if(y & 1) re = re * x % mod;
x = x * x % mod;
y >>= 1;
}
return re;
}
LL C(int x, int y) {
return fac[x] * inv[y] % mod * inv[x - y] % mod;
}
void dfs(int dep, int tot) {
if(dep == p + 1) {
if(tot) return;
for(int i = 0; i <= q; i++) st[++len] = node(ls[1], ls[2], ls[3], i);
return;
}
for(int i = tot; i >= 0; i--) ls[dep] = i, dfs(dep + 1, tot - i);
}
void predoit() {
fac[0] = inv[0] = 1;
for(int i = 1; i <= 20; i++) fac[i] = 1LL * i * fac[i - 1] % mod, inv[i] = ksm(fac[i], mod - 2);
}
void work(const node &a, const node &b, int x, int y) {
int a1 = a.st[0], b1 = a.st[1], c1 = a.st[2], d1 = a.num;
int a2 = b.st[0], b2 = b.st[1], c2 = b.st[2], d2 = b.num;
if(d1 + 1 == d2) {
if(a1 == b2 && b1 == c2 && !c1) return (void)(A.ju[y][x]++);
} else if(d1 == d2) {
if(a1 == b2 && b1 == c2 && !c1) return;
if(a1 >= b2 && b1 >= c2) return (void)(A.ju[y][x] = C(a1, a1 - b2) * C(b1, b1 - c2) % mod);
}
}
void Build_Matrix() {
dfs(1, n);
#ifdef olinr
for(int i = 1; i <= len; i++) printf("%d %d %d %d\n", st[i].st[0], st[i].st[1], st[i].st[2], st[i].num);
#endif
for(int i = 1; i <= len; i++)
for(int j = 1; j <= len; j++)
work(st[i], st[j], i, j);
beg.ju[1][1] = 1;
}
void query() {
beg = A.ksm(m) * beg;
LL ans = 0;
for(int i = 1; i <= len; i++) (ans += beg.ju[i][1]) %= mod;
printf("%lld", ans);
}
int main() {
freopen("b.in", "r", stdin);
freopen("b.out", "w", stdout);
n = in(), m = in(), p = in(), q = in();
predoit();
Build_Matrix();
query();
return 0;
}

2019.2.26考试T2 矩阵快速幂加速DP的更多相关文章

  1. [bzoj1009](HNOI2008)GT考试 (kmp+矩阵快速幂加速递推)

    Description 阿 申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字.他的不吉利数学 A1A2...Am(0&l ...

  2. bzoj1009 [HNOI2008]GT考试——KMP+矩阵快速幂优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1009 字符串计数DP问题啊...连题解都看了好多好久才明白,别提自己想出来的蒟蒻我... 首 ...

  3. 【bzoj1009】[HNOI2008]GT考试(矩阵快速幂优化dp+kmp)

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1009 这道题一看数据范围:$ n<=10^9 $,显然不是数学题就是矩乘快速幂优 ...

  4. HDU 5950 - Recursive sequence - [矩阵快速幂加速递推][2016ACM/ICPC亚洲区沈阳站 Problem C]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5950 Farmer John likes to play mathematics games with ...

  5. CH 3401 - 石头游戏 - [矩阵快速幂加速递推]

    题目链接:传送门 描述石头游戏在一个 $n$ 行 $m$ 列 ($1 \le n,m \le 8$) 的网格上进行,每个格子对应一种操作序列,操作序列至多有 $10$ 种,分别用 $0 \sim 9$ ...

  6. 2018.10.23 bzoj1297: [SCOI2009]迷路(矩阵快速幂优化dp)

    传送门 矩阵快速幂优化dp简单题. 考虑状态转移方程: f[time][u]=∑f[time−1][v]f[time][u]=\sum f[time-1][v]f[time][u]=∑f[time−1 ...

  7. HDU5411——CRB and Puzzle——————【矩阵快速幂优化dp】

    CRB and Puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  8. Codeforces Round #420 (Div. 2) E. Okabe and El Psy Kongroo DP+矩阵快速幂加速

    E. Okabe and El Psy Kongroo     Okabe likes to take walks but knows that spies from the Organization ...

  9. HDU 1757 矩阵快速幂加速递推

    题意: 已知: 当x<10时:f(x)=x 否则:f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + --+ a9 * f(x-10); 求:f(x ...

随机推荐

  1. DCloud-5+Runtime:杂项

    ylbtech-DCloud-5+Runtime:杂项 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部 ...

  2. PostgreSQL 监控磁盘使用

    监控磁盘使用 1. 判断磁盘用量 每个表都有一个主要的堆磁盘文件,大多数数据都存储在其中.如果一个表有着可能会很宽(尺寸大)的列, 则另外还有一个TOAST文件与这个表相关联, 它用于存储因为太宽而不 ...

  3. 找不到引用microsoft.office.core解决办法 via mrcjiong

    在控制面板中,选择"添加删除程序",找到office ,选择"更改",在对话框中选择"添加删除功能",然后选择自定义安装,添加上office ...

  4. java selenium webdriver第一讲 seleniumIDE

    Selenium是ThoughtWorks公司,一个名为Jason Huggins的测试为了减少手工测试的工作量,自己实现的一套基于Javascript语言的代码库 使用这套库可以进行页面的交互操作, ...

  5. 如何通过outline为SQL语句指定执行计划

    创建测试表 以用户jyu连接,创建测试表 SQL> conn jyu/jyu; Connected. SQL> create table t (id number, name varcha ...

  6. matlab学习笔记(4)

    第9章 数学建模函数 曲线拟合: 多项式拟合: polyfit()函数:采用最小二乘法进行多项式拟合. polyfit(x,y,n);   %对于数据集[x,y],找到次数为n的多项式. [p E] ...

  7. Web访问中的角色与协议

  8. Java开源中文分词类库

      IKAnalyzer  IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包.从2006年12月推出1.0版开始,IKAnalyzer已经推出了3个大版本.最初,它是以开 ...

  9. bzoj4391 [Usaco2015 dec]High Card Low Card

    传送门 分析 神奇的贪心,令f[i]表示前i个每次都出比对方稍微大一点的牌最多能赢几次 g[i]表示从i-n中每次出比对方稍微小一点的牌最多赢几次 ans=max(f[i]+g[i+1]) 0< ...

  10. loj2395 [JOISC 2017 Day 2]火车旅行

    传送门 分析 我们知道无论往左走还是往右走一定都是往不低于这个点的地方走 于是我们可以考虑用倍增来维护一个点向左和向右走$2^i$最远分别能走到哪里 我们可以先用单调栈求出直走一步的情况,之后再处理倍 ...