bzoj 3120 矩阵优化DP
我的第一道需要程序建矩阵的矩阵优化DP。
题目可以将不同的p分开处理。
对于p==0 || p==1 直接是0或1
对于p>1,就要DP了。这里以p==3为例:
设dp[i][s1][s2][r]为前i列,结尾为0的有s1行(0表示女生,1表示男生),结尾为01的有s2个,结尾为011的有n-s1-s2个,有r列全是1的方案数。
状态这么复杂,看起来一点也不能用矩阵优化,但我们可以将状态(s1,s2,r)hash成整数,然后建立状态之间的转移。
收获:
这种m超过10^7的一般都要用矩阵优化,如果状态很复杂,可以将复杂的状态(但一般不多)hash成整数,然后用计算机建立状态之间的转移,然后就可以用矩阵优化了。
/**************************************************************
Problem: 3120
User: idy002
Language: C++
Result: Accepted
Time:24504 ms
Memory:2616 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#define M 1000000007
#define maxs 200 typedef long long dint; int n, p, q;
dint m;
int comb[][]; void init_comb() {
for( int i=; i<=; i++ )
for( int j=; j<=i; j++ ) {
if( j== || i==j )
comb[i][j]=;
else
comb[i][j] = (comb[i-][j]+comb[i-][j-]);
}
}
struct Matrix {
int n;
dint v[maxs][maxs];
void init( int nn ) {
n=nn;
for( int i=; i<n; i++ )
for( int j=; j<n; j++ )
v[i][j]=;
}
void make_unit( int nn ) {
n=nn;
for( int i=; i<n; i++ )
for( int j=; j<n; j++ )
v[i][j] = i==j;
}
Matrix operator*( const Matrix & b ) const {
const Matrix & a = *this;
Matrix rt;
memset( &rt, , sizeof(rt) );
rt.n = b.n;
for( int k=; k<n; k++ ) {
for( int i=; i<n; i++ ) {
if( a.v[i][k] ) {
for( int j=; j<n; j++ ) {
if( b.v[k][j] ) {
rt.v[i][j] += (a.v[i][k]*b.v[k][j])%M;
if( rt.v[i][j]>=M ) rt.v[i][j]-=M;
}
}
}
}
}
/*
for( int i=0; i<n; i++ ) {
for( int j=0; j<n; j++ ) {
rt.v[i][j] = 0;
for( int k=0; k<n; k++ ) {
rt.v[i][j] += (a.v[i][k]*b.v[k][j])%M;
if( rt.v[i][j]>=M )
rt.v[i][j]-=M;
}
}
}
*/
return rt;
}
}; Matrix mpow( Matrix a, dint b ) {
Matrix rt;
for( rt.make_unit(a.n); b; b>>=,a=a*a )
if( b& ) rt=(rt*a);
return rt;
}
namespace Sec1 {
void sov(){
if( p== ) printf( "0\n" );
else if( p== ) printf( "1\n" );
}
}
namespace Sec2 {
int info[maxs][], idx[][], tot;
Matrix trans;
void init() {
for( int r=; r<=q; r++ )
for( int a=; a<=n; a++ ) {
info[tot][] = a;
info[tot][] = n-a;
info[tot][] = r;
idx[a][r] = tot;
tot++;
}
trans.init(tot);
for( int s=; s<tot; s++ ) {
int a=info[s][], r=info[s][];
for( int sa=; sa<=a; sa++ ) {
int na=n-sa, nr=r+(sa==n);
if( nr>q ) continue;
int ns=idx[na][nr];
trans.v[s][ns] = comb[a][sa];
}
}
}
void sov() {
init();
trans = mpow( trans, m );
int row = idx[n][];
dint ans=;
for( int i=; i<tot; i++ ) {
ans += trans.v[row][i];
if( ans>=M ) ans-=M;
}
printf( "%lld\n", ans );
}
}
namespace Sec3 {
int info[maxs][], idx[][][], tot;
Matrix trans;
void init() {
for( int r=; r<=q; r++ )
for( int a=; a<=n; a++ )
for( int b=; b<=n-a; b++ ) {
info[tot][] = a;
info[tot][] = b;
info[tot][] = n-a-b;
info[tot][] = r;
idx[a][b][r] = tot;
tot++;
}
trans.n = tot;
for( int s=; s<tot; s++ ) {
int a=info[s][], b=info[s][], c=info[s][], r=info[s][];
for( int sa=; sa<=a; sa++ )
for( int sb=; sb<=b; sb++ ) {
int na=c+a-sa+b-sb, nb=sa, nr=r+(sa+sb==n);
if( nr>q ) continue;
int ns = idx[na][nb][nr];
trans.v[s][ns] = comb[a][sa]*comb[b][sb];
}
}
}
void sov(){
init();
trans = mpow( trans, m );
int row = idx[n][][];
dint ans=;
for( int i=; i<tot; i++ ) {
ans += trans.v[row][i];
if( ans>=M ) ans-=M;
}
printf( "%lld\n", ans );
}
} int main() {
scanf( "%d%lld%d%d", &n, &m, &p, &q );
init_comb();
if( p<= ) Sec1::sov();
else if( p== ) Sec2::sov();
else if( p== ) Sec3::sov();
}
bzoj 3120 矩阵优化DP的更多相关文章
- 矩阵优化dp
链接:https://www.luogu.org/problemnew/show/P1939 题解: 矩阵优化dp模板题 搞清楚矩阵是怎么乘的构造一下矩阵就很简单了 代码: #include < ...
- HDU - 2294: Pendant(矩阵优化DP&前缀和)
On Saint Valentine's Day, Alex imagined to present a special pendant to his girl friend made by K ki ...
- [六省联考2017]组合数问题 (矩阵优化$dp$)
题目链接 Solution 矩阵优化 \(dp\). 题中给出的式子的意思就是: 求 nk 个物品中选出 mod k 为 r 的个数的物品的方案数. 考虑朴素 \(dp\) ,定义状态 \(f[i][ ...
- bzoj 1009 [HNOI2008]GT考试——kmp+矩阵优化dp
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1009 首先想到 确保模式串不出现 就是 确保每个位置的后缀不是该模式串. 为了dp,需要记录 ...
- [Sdoi2017]序列计数 矩阵优化dp
题目 https://www.lydsy.com/JudgeOnline/problem.php?id=4818 思路 先考虑没有质数限制 dp是在同余系下的,所以\(f[i][j]\)表示前i个点, ...
- 矩阵优化DP类问题应用向小结
前言 本篇强调应用,矩阵的基本知识有所省略(也许会写篇基础向...). 思想及原理 为什么Oier们能够想到用矩阵来加速DP呢?做了一些DP题之后,我们会发现,有时候DP两两状态之间的转移是定向的,也 ...
- 洛谷P3193 GT考试 kmp+矩阵优化dp
题意 求\(N\)位数字序列(可以有前导0)中不出现某\(M\)位子串的个数,模\(K\). \(N<=10^9,M<=20,K<=1000\) 分析 设\(dp[i][j]\)表示 ...
- $[TJOI2017]$ 可乐 矩阵优化$dp$
\(Sol\) 设\(f_i\)为到第\(i\)秒的方案数,显然\(f_i=\)在第\(i\)秒前爆炸的方案数+在第\(i\)秒爆炸的方案数+在第\(i\)秒停下的方案数+在第\(i\)秒走向下一个城 ...
- bzoj 1096 斜率优化DP
首先比较容易的看出来是DP,w[i]为前i个工厂的最小费用,那么w[i]=min(w[j-1]+cost(j,i))+c[i],但是这样是不work的,复杂度上明显过不去,这样我们考虑优化DP. 设A ...
随机推荐
- lintcode 443.岛屿的个数
在v2ex上看到有人提到了这个,感觉挺简单的,没忍住还是试一下.... 基本的染色法. AC代码: public class Solution { /** * @param grid a boolea ...
- 【文件上传】jquery之ajaxfileupload异步上传插件
来自:http://www.blogjava.net/sxyx2008/archive/2010/11/02/336826.html 由于项目需求,在处理文件上传时需要使用到文件的异步上传.这里使用J ...
- ubuntu永久修改主机名
1.查看主机名 在Ubuntu系统中,快速查看主机名有多种方法:其一,打开一个GNOME终端窗口,在命令提示符中可以看到主机名,主机名通常位于“@”符号后:其二,在终端窗口中输入命令:hostname ...
- mysql中列的增删改
增加列: ); ) after id; ) first; 修改列名: ); #change可改名字与字段类型 mysql> alter table a change uid uid int; Q ...
- flask插件系列之SQLAlchemy基础使用
sqlalchemy是一个操作关系型数据库的ORM工具.下面研究一下单独使用和其在flask框架中的使用方法. 直接使用sqlalchemy操作数据库 安装sqlalchemy pip install ...
- dpkg的用法 (转)
dpkg是一个Debian的一个命令行工具,它可以用来安装.删除.构建和管理Debian的软件包. 下面是它的一些命令解释: 1)安装软件 命令行:dpkg -i <.deb file name ...
- Android仿新浪新闻SlidingMenu界面的实现 .
先看看原图: 如图所示,这种侧滑效果以另一种方式替代了原先tab导航的那种用户体验方式 给人耳目一新的感觉,现已被广大知名应用所效仿,如新浪新闻,网易新闻,人人网等 那么这种效果该如何实现呢?那就需要 ...
- 模块定义文件.def
一作用 DLL中导出函数的声明有两种方式:一种为在函数声明中加上__declspec(dllexport),这里不再举例说明:另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供 ...
- meta标签的使用方法(PC端)
<!DOCTYPE html> <html lang="en"> <head> <!--设定页面使用的字符集--> <meta ...
- Web开发:URL编码与解码
通常如果一样东西需要编码,说明这样东西并不适合传输.原因多种多样,如Size过大,包含隐私数据,对于Url来说,之所以要进行编码,是因为Url中有些字符会引起歧义. 例如Url参数字符串中使用key= ...