嘟嘟嘟




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

换成这个,我就不会了。

我一直想枚举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. idea代码快捷

    idea代码快捷:main函数快捷:psvmfor循环快捷:fori.foreach系统输出快捷:sout.serr 更多的提示可以按Ctrl+ J 进行查看 更改快捷:File-->Setti ...

  2. css 样式表的书写顺序

    display || visibility list-style : list-style-type || list-style-position || list-style-image positi ...

  3. Linux PCI设备驱动的实现思路与思想

    概述 1.PCI设备一般都具有双重身份,一方面作为PCI设备注册到Linux内核,另一方面,作为字符设备或者块设备,或者网络设备注册到Linux内核,所以,在看PCI设备时一定要注意到这点. 2. 一 ...

  4. CSS回顾(基础知识,元素,选择器,盒子,颜色)

    元素分类: 1.行级元素:内联元素  inline 特征:内容决定元素所占位置,不可以通过CSS改变宽高 span  strong   em  a  del 2.块级元素:block特征:独占一行,可 ...

  5. vue使用axios请求后端数据

    1. 安装axios $ npm install axios 2.在main.js里面导入axios import axios from 'axios' Vue.prototype.$http = a ...

  6. java笔记----JVM内存

    运行时数据区包括:虚拟机栈区,堆区,方法区,本地方法栈,程序计数器 虚拟机栈区 :也就是我们常说的栈区,线程私有,存放基本类型,对象的引用和 returnAddress ,在编译期间完成分配. 堆区  ...

  7. MyBatis笔记----MyBatis查询表全部的两种方法:XML与注解

    查询单条信息的在 http://www.cnblogs.com/tk55/p/6659285.html  已经有了 XML 修改UserMapper.xml <?xml version=&quo ...

  8. Python PEP-8编码风格指南中文版

    #PEP 8 – Python编码风格指南 PEP: 8 Title: Style Guide for Python Code Author: Guido van Rossum , Barry War ...

  9. f.lux 自动调节显示器色温

    我的环境 f.lux 我的使用感受是让屏幕看起来舒服一些,因为我有近视,所以需要保护眼睛. f.lux官网:https://justgetflux.com/ f.lux v4.47 windows 1 ...

  10. JavaScript获取IE版本号与HTML设置ie文档模式

    JavaScript获取IE版本代码: var gIE = getIE(); alert(gIE.version) function getIE() { var rmsie = /(msie) ([\ ...