「CSA49」Bunny on Number Line

题目大意:有一个人从0开始走,每次可以向前走一步或者回到1,那么会产生一个位置序列,其中给出 \(k\) 个位置是好的。定义一个位置序列是好的,当前仅当其有恰好 \(n\) 个位置是好的,且最后一个位置是好的,相邻两个好的位置距离不超过 \(m\) ,求本质不同的好的序列的长度之和。两个序列本质不同当且仅当存在一个位置满足在其中一个序列中上的位置是好的,另外一个不是。

解题思路:问题转换一下,将好的位置看作 1 ,其它的位置看作 0,组成一个01字符串。那么每次往后走到一个好的位置,相当于往后接一个以1结尾的前缀,然后求这样所得的所有不同的字符串的长度之和。实际上所有1和0都是一样的,区分字符串只有每个1前面的0的数量不同。于是可以重新定义字符 \(b_i =a_i-a_{i-1}\) 。问题转化为求出所有由 \(b\) 组成的合法的不同字符串的长度之和,事实上求长度之和要用到方案数,而方案数会求了长度之和自然就能求了,所以下面就讲方案数怎么求。

考虑一个朴素的做法,令 \(dp(i,j)\) 表示当前长度为 \(i\) 的字符串末尾的字符是 \(b_j\) 的方案数,考虑 \(dp(i,j)\) 向后转移本质上是原串在某一时刻向后加了一个以 \(b_j\) 结尾的前缀,然后转移到这个前缀后面的那个字符。且这个前缀还必须与当前确定的串的后缀匹配,不然就会产生不合法的方案数。分析一下会发现这是一个kmp不断跳失配指针的过程,直接跳转移即可。不过还有几个情况要讨论一下,如果出现之前长度较长的前缀已经能转移到某个 \(c\) ,当前也要转移到 \(c\) ,此时会发现转移后的串本质是一样的,只是 \(j\) 的大小不一样,而由于长的串跳失配指针一定能包含短的串,所以只转移到较长的那个即可。另外 \(b_1\) 是一个通配符可以匹配 \([a_1,m]\) 之间的所有字符,因为其可以不断跳若干次1再走到第一个好的位置,所以要对与 \(b_1\) 的匹配加以特判。

然后这个转移求完之后同理可以利用方案数来求总长度,只需要对每个字符加权计算即可,\(b_1\) 的权是 \(\sum_{i=a_1}^mi\) ,最后矩阵快速幂优化一下这个转移即可,总复杂度 \(O(k^3logn)\) ,用 BM 可以做到 \(O(k^2)\) 。

code

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T & x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
} #define int ll
#define fi first
#define se second const int N = 105, mod = 1e9+7; map<int, int> mp;
int nxt[N], a[N], b[N], n, m, k, ans;
inline void add(int &x, int y){ x = x + y >= mod ? x + y - mod : x + y; }
inline void del(int &x, int y){ x = x - y < 0 ? x - y + mod : x - y; } struct Matrix{
pair<int, int> a[N][N];
inline Matrix(){ memset(a, 0, sizeof(a)); }
inline Matrix operator * (const Matrix &B) const{
Matrix ans;
for(int i = 1; i <= k; i++)
for(int j = 1; j <= k; j++)
for(int p = 1; p <= k; p++){
add(ans.a[i][j].fi, a[i][p].fi * B.a[p][j].fi % mod);
add(ans.a[i][j].se, a[i][p].fi * B.a[p][j].se % mod);
add(ans.a[i][j].se, a[i][p].se * B.a[p][j].fi % mod);
}
return ans;
}
}A, B; inline Matrix Pow(Matrix A, int b){
Matrix ans = A; b--;
for(; b; b >>= 1, A = A * A)
if(b & 1) ans = ans * A;
return ans;
} inline int same(int x, int y){
return y == 1 ? (b[x] >= a[1]) : (b[x] == b[y]);
}
signed main(){
read(k), read(m), read(n), nxt[0] = -1;
for(int i = 1; i <= k; i++) read(a[i]), b[i] = a[i] - a[i-1];
for(int i = 2, j = 0; i <= k; nxt[i++] = ++j)
while(~j && !same(i, j + 1)) j = nxt[j];
int tot = (m - a[1] + 1), sum = tot * (a[1] + m) / 2 % mod;
for(int i = 1; i <= k; i++){
mp.clear();
for(int p = i; p; p = nxt[p]) if(!mp[b[p+1]]){
A.a[p+1][i] = make_pair(1ll, b[p+1]);
if(b[p+1] >= a[1])
del(A.a[1][i].fi, 1), del(A.a[1][i].se, b[p+1]);
mp[b[p+1]] = 1;
}
add(A.a[1][i].fi, tot), add(A.a[1][i].se, sum);
}
if(n == 1) return cout << sum, 0;
B.a[1][1] = make_pair(tot, sum), A = Pow(A, n - 1) * B;
for(int i = 1; i <= k; i++) add(ans, A.a[i][1].se);
cout << ans;
}

「CSA49」Bunny on Number Line的更多相关文章

  1. 「CSA49」Card Collecting Game

    「CSA49」Card Collecting Game 题目大意:有 \(n\) 种卡片,每种有 \(b_i\) 张,如果一个人集齐 \(k\) 张第 \(i\) 种卡片,那么其能获得的得分是 \(\ ...

  2. 「POJ3696」The Luckiest number【数论,欧拉函数】

    # 题解 一道数论欧拉函数和欧拉定理的入门好题. 虽然我提交的时候POJ炸掉了,但是在hdu里面A掉了,应该是一样的吧. 首先我们需要求的这个数一定可以表示成\(\frac{(10^x-1)}{9}\ ...

  3. 「USACO16OPEN」「LuoguP3147」262144(区间dp

    P3147 [USACO16OPEN]262144 题目描述 Bessie likes downloading games to play on her cell phone, even though ...

  4. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

  5. 「2014-2-26」Unicode vs. UTF-8 etc.

    目测是个老问题了.随便一搜,网上各种总结过.这里不辞啰嗦,尽量简洁的备忘一下. 几个链接,有道云笔记链接,都是知乎上几个问题的摘录:阮一峰的日志,1-5 还是值得参考,但是之后的部分则混淆了 Wind ...

  6. 「2014-2-6」TokuMX and MongoDB related materials collection

    简介参考 TokuMX 和 MongoDB 各自的官方站点.       ##  Tokutek 最重要的特点和 marketing word 是所谓 fractal tree indexing te ...

  7. 「译」JavaScript 的怪癖 1:隐式类型转换

    原文:JavaScript quirk 1: implicit conversion of values 译文:「译」JavaScript 的怪癖 1:隐式类型转换 译者:justjavac 零:提要 ...

  8. 「SCOI2015」小凸想跑步 解题报告

    「SCOI2015」小凸想跑步 最开始以为和多边形的重心有关,后来发现多边形的重心没啥好玩的性质 实际上你把面积小于的不等式列出来,发现是一次的,那么就可以半平面交了 Code: #include & ...

  9. AC日记——「SCOI2016」背单词 LiBreOJ 2012

    #2012. 「SCOI2016」背单词 思路: Orz: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...

随机推荐

  1. D - Binary Lexicographic Sequence URAL - 1081 (贪心)

    题目链接:https://cn.vjudge.net/contest/275079#problem/D 具体思路:首先,我们可以观察到1-n位数的种数连起来是一个很有规律的数列,然后我们开始倒序建立. ...

  2. python设计模式之内置装饰器使用(四)

    前言 python内部有许多内建装饰器,它们都有特别的功能,下面对其归纳一下. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python设计模式之装饰 ...

  3. FPGA编码规则检查表

    FPGA编码规则检查表 -----------------------摘自<FPGA软件测试与评价技术> 中国电子信息产业发展研究院 | 编著 1.一个单独的文件应该只包含一个单独的mod ...

  4. 使用ctypes在Python中调用C++动态库

    使用ctypes在Python中调用C++动态库 入门操作 使用ctypes库可以直接调用C语言编写的动态库,而如果是调用C++编写的动态库,需要使用extern关键字对动态库的函数进行声明: #in ...

  5. LCD驱动分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/21559153 1.S3C2440上LCD驱动 (FrameBuffer)实例开发讲解 其 ...

  6. ubuntu sougou输入法

    1, 打开搜狗输入法Linux版的官网http://pinyin.sogou.com/linux/?r=pinyin,并下载你需要的版本,这里选择64位版. 2,在Ubuntu14.01下可以直接点击 ...

  7. 配置kernel的log buf大小(如果kmsg log被覆盖)

    如果在打印kmsg log时发现log被覆盖,log 的buf不够大可以使用默认配置调buf: defconfig CONFIG_LOG_BUF_SHIFT=20  (默认是17  2的17次方)   ...

  8. 64_o1

    OCE-devel-0.18.1-1.fc26.i686.rpm 15-May-2017 18:37 5634474 OCE-devel-0.18.1-1.fc26.x86_64.rpm 15-May ...

  9. 百度2017春招<空间中最大三角形面积的问题>

    题目: 三维空间中有N个点,每个点可能是三种颜色的其中之一,三种颜色分别是红绿蓝,分别用'R', 'G', 'B'表示. 现在要找出三个点,并组成一个三角形,使得这个三角形的面积最大.但是三角形必须满 ...

  10. oracle相关命令收集-张

    orcle相关命令收集 1,用管理员登陆 /as sysdba:2, 更改用户密码 alter user name identified by password: alter user exptest ...