嘟嘟嘟




要是求交错序列的个数和就好了,那我一秒就能切。

换成这个,我就不会了。

我一直想枚举1的个数,然后算出在长度为\(n\)的序列里,有多少个合法的序列,然后又觉得这好像是什么插板法,但是每一个盒子里必须有球,还不会。查了一下发现这东西\(O(1)\)还求不了,于是彻底放弃了。




正解是这样的,首先还得稍微推一下式子。

\[x ^ a y ^ b = (n - y) ^ a y ^ b
\]

然后利用二项式定理

\[(n - y) ^ a y ^ b = \sum _ {i = 0} ^ a C_{a} ^ {i} n ^ i (-1) ^ {a - i} y ^ {a + b - i}
\]

于是我们发现,只用求\(y\)的和的\(x\)次幂就行了。

怎么求咧,这时候就要用dp了。

令\(dp[i][j][0 / 1]\)表示长度为\(i\)的序列中,这一位填0 / 1时1的个数的\(j\)次幂。那么分情况转移:

当这一位填0时,1的个数不变,则\(dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1]\)。

当这一位填1时,考虑\(y\)加了1,则\((y + 1) ^ j = \sum _ {k = 0} ^ {j} C_{j} ^ {k} y ^ j\),于是有\(dp[i][j][1] = \sum _ {k = 0} ^ {j} C_{j} ^ {k} dp[i - 1][j][0]\)

讲真这时候维护前缀和\(O(n)\)dp应该已经能过了,但是交上去就是TLE,所以只能改成矩乘了(还得卡常)。




矩阵是一个边长为\(2(a + b)\)的正方形矩阵,用样例一构造后的矩阵张这个样子:

1 0 0 0 1 0 0 0

0 1 0 0 0 1 0 0

0 0 1 0 0 0 1 0

0 0 0 1 0 0 0 1

1 0 0 0 0 0 0 0

1 1 0 0 0 0 0 0

1 2 1 0 0 0 0 0

1 3 3 1 0 0 0 0




总结一下,感觉上点难度的dp题有一部分就是在dp之前先要推一推式子,推到觉得可以dp的时候再开始dp。至于啥时候觉得可以dp,估计这就得靠刷题吧……

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 205;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
} int n, a, b, mod, Max;
struct Mat
{
ll a[maxn][maxn];
In Mat operator * (const Mat& oth)const
{
static Mat ret; Mem(ret.a, 0);
for(int i = 0; i <= Max; ++i)
for(int j = 0; j <= Max; ++j)
{
for(int k = 0; k <= Max; ++k) ret.a[i][j] += a[i][k] * oth.a[k][j];
ret.a[i][j] %= mod;
}
return ret;
}
}f;
ll C[maxn][maxn];
In void init()
{
for(int i = 0; i <= a + b; ++i) C[i][0] = 1;
for(int i = 1; i <= a + b; ++i)
for(int j = 1; j <= i; ++j) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
Mem(f.a, 0); Max = ((a + b) << 1) + 1;
for(int i = 0; i <= a + b; ++i) f.a[i][i] = f.a[i][a + b + 1 + i] = 1;
for(int i = 0; i <= a + b; ++i)
for(int j = 0; j <= i; ++j) f.a[a + b + 1 + i][j] = C[i][j];
} In Mat quickpow(Mat A, ll b)
{
Mat ret; Mem(ret.a, 0);
for(int i = 0; i <= Max; ++i) ret.a[i][i] = 1;
for(; b; b >>= 1, A = A * A)
if(b & 1) ret = ret * A;
return ret;
} ll ans[maxn];
int main()
{
n = read(), a = read(), b = read(), mod = read();
init();
Mat A = quickpow(f, n);
for(int i = 0; i <= a; ++i)
{
for(int j = 0; j <= Max; ++j) ans[i] += A.a[i][j];
for(int j = 0; j <= Max; ++j) ans[i] += A.a[a + b + 1 + i][j];
ans[i] %= mod;
}
ll Ans = 0, tp = 1;
for(int i = 0, flg = pow(-1, a); i <= a; ++i, tp = tp * n % mod, flg *= (-1))
Ans = (Ans + C[a][i] * tp % mod * (A.a[a + b - i][0] + A.a[a + b - i + a + b + 1][0]) * flg % mod + mod) % mod;
write(Ans), enter;
return 0;
}

[CQOI2018]交错序列的更多相关文章

  1. 【BZOJ5298】[CQOI2018]交错序列(动态规划,矩阵快速幂)

    [BZOJ5298][CQOI2018]交错序列(动态规划,矩阵快速幂) 题面 BZOJ 洛谷 题解 考虑由\(x\)个\(1\)和\(y\)个\(0\)组成的合法串的个数. 显然就是把\(1\)当做 ...

  2. [CQOI2018]交错序列 (矩阵快速幂,数论)

    [CQOI2018]交错序列 \(solution:\) 这一题出得真的很好,将原本一道矩阵快速幂硬生生加入组合数的标签,还那么没有违和感,那么让人看不出来.所以做这道题必须先知道(矩阵快速幂及如何构 ...

  3. BZOJ5298 CQOI2018 交错序列 【DP+矩阵快速幂优化】*

    BZOJ5298 CQOI2018 交错序列 [DP+矩阵快速幂优化] Description 我们称一个仅由0.1构成的序列为"交错序列",当且仅当序列中没有相邻的1(可以有相邻 ...

  4. bzoj 5298: [Cqoi2018]交错序列

    Description 我们称一个仅由0.1构成的序列为"交错序列",当且仅当序列中没有相邻的1(可以有相邻的0).例如,000,001 ,101,都是交错序列,而110则不是.对 ...

  5. BZOJ5298 [CQOI2018] 交错序列 | 矩阵乘法和一个trick

    题面 求所有长度为\(n\)的.没有相邻的1的01序列中,若0有\(x\)个.1有\(y\)个,\(x^ay^b\)之和(对\(m\)取模). \(n \le 10^7, m \le 10^8, 0 ...

  6. BZOJ5298 CQOI2018交错序列(动态规划+矩阵快速幂)

    显然答案为Σkb·(n-k)a·C(n-k+1,k).并且可以发现ΣC(n-k,k)=fibn.但这实际上没有任何卵用. 纯组合看起来不太行得通,换个思路,考虑一个显然的dp,即设f[i][j][0/ ...

  7. [BZOJ5298][CQOI2018]交错序列(DP+矩阵乘法)

    https://blog.csdn.net/dream_maker_yk/article/details/80377490 斯特林数有时并没有用. #include<cstdio> #in ...

  8. 【[CQOI2018]交错序列】

    这个题简直有毒,\(O((a+b)^3logn)\)的做法不卡常只比\(O(2^n*n)\)多\(10\)分 看到\(a\)和\(b\)简直小的可怜,于是可以往矩阵上联想 发现这个柿子有些特殊,好像可 ...

  9. cqoi2018

    题解: 很多模板题 第一次写莫队还比较顺利 除了把排序的cmp写错..(还第一次遇到) 这题分块也可以 先预处理出g[i][j]代表前i个块,颜色为j的有多少种 f[i][j]表示i-j的块能构成多少 ...

随机推荐

  1. js/es6 元素拖动

    元素事件:鼠标按下事件/鼠标移动事件/鼠标松开事件 元素样式:让元素脱离文档流,采用绝对定位的方式. 一.鼠标按下事件 当鼠标在元素上面按下时,保存元素的初始偏移量和鼠标按下时的坐标,然后在状态变量里 ...

  2. thinkphp模板中,checkbox回显问题

    thinkphp 模板里面可以这样写包含操作 //in 标签 <in name="变量名" value="值1,值2,...">要输出的内容< ...

  3. K8S 高级调度方式

    可以使用高级调度分为: 节点选择器: nodeSelector.nodeName 节点亲和性调度: nodeAffinity Pod亲和性调度:PodAffinity Pod反亲和性调度:podAnt ...

  4. vue单页应用添加百度统计

    前言 申请百度统计后,会得到一段JS代码,需要插入到每个网页中去,在Vue.js项目首先想到的可能就是,把统计代码插入到index.html入口文件中,这样就全局插入,每个页面就都有了;这样做就涉及到 ...

  5. 快速上手ABP - Angular部分 - 如何最快速度了解相关API。

    不是google,不是angular官网,而是在Visual Studio Code选中这个API对象,鼠标右键,选"Go to Definition" 例子:要想了解FormGr ...

  6. Java的关键字

    下面列出Java关键字.这些保留字不能用于常量.变量和任标识示字符的名称 没事儿时多背背,对你没有坏处哒! 类别 关键字 说明 访问控制 private 私有的 protected 受保护的 publ ...

  7. SpringBoot-学习笔记

    启动方式 运行main方法 @SpringBootApplication public class BootApplication { public static void main(String[] ...

  8. Spring整合ActiveMq消息队列

    ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管JMS规范出台已经是很久 ...

  9. [转] vi/vim命令模式和编辑模式各种操作

    摘要:vi 编辑器是最常用的文档创建和编辑工具,初学者应该学会简单应用vi ,学会在vi 中做简单的修改.删除.插入.搜索及替换作业:如果您是新手,不妨看看本文,或许这篇文档能让您在最短的时间内学会v ...

  10. 使用 new XMLHttpRequest() 制作下载文件进度条

    mui 进度控件使用方法: 检查当前容器(container控件)自身是否包含.mui-progressbar类: 当前容器包含.mui-progressbar类,则以当前容器为目标控件,直接显示进度 ...