「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. BestCoder Round #41 记。

    大概整个过程都是很绝望的吧. 发现自己在七点之前是肯定搞不定网了..有冲动跑到机房去打 但是又不喜欢那样的气氛 这可是shi的场呢...好难过啊... 后来..好像是在和lyd讨论怎么把网络复原的过程 ...

  2. 【洛谷 P3648】 [APIO2014]序列分割 (斜率优化)

    题目链接 假设有\(3\)段\(a,b,c\) 先切\(ab\)和先切\(bc\)的价值分别为 \(a(b+c)+bc=ab+bc+ac\) \((a+b)c+ab=ab+bc+ac\) 归纳一下可以 ...

  3. jQuery domready

    在jQuery里面,我们可以看到两种写法: $(function(){ //todo }) $(document).ready(function(){ //todo }) 这两个方法的效果都是一样的, ...

  4. WHY学习python?

    1.python更容易上手 2.功能库很多,不用重复造轮子 3.能干的事情很多(网站开发,爬虫,自动化运维,数据分析,游戏开发,人工智能) 网站开发:豆瓣,知乎 网站框架:django (姜狗) py ...

  5. Linux SCIM/fcitx/ibus 输入法

    现在很多发行版linux一般都是装好scim scim-tables-zh 重启就行 但有时重启后还是不能调用 可以用如下方法: 添加文件: sudo gedit /etc/X11/xinit/xin ...

  6. Linux CentOS 6.9(图形界面)安装中文输入法

    安装步骤 1. 切换到 root 用户,执行 yum -y install "@Chinese Support" 2. 退出终端,选择桌面菜单中 "System" ...

  7. 在新版linux上编译老版本的kernel出现kernel/timeconst.h] Error 255

    在使用ubuntu16.4编译Linux-2.6.31内核时出现这样的错误 可以修改timeconst.pl的内容后正常编译. 以下是编译错误提示的内容: Can't use 'defined(@ar ...

  8. Ubuntu 下查看已安装的软件

    Ubuntu 下如何查看已安装的软件 1.查看安装的所有软件 dpkg -l 例如: dpkg -l | grep ftp 2.查看软件安装的路径 dpkg -L | grep ftp 也可以用 wh ...

  9. HDU 1024 Max Sum Plus Plus(dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024 题目大意:有多组输入,每组一行整数,开头两个数字m,n,接着有n个数字.要求在这n个数字上,m块 ...

  10. mac 安装mongodb与常用操作

    1.安装 brew update brew install mongodb 2.启动mongo mongod --config /usr/local/etc/mongod.conf 3.启动 mong ...