「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. 【BZOJ】4873: [Shoi2017]寿司餐厅

    [题目]#2146. 「SHOI2017」寿司餐厅 [题意]给定n种寿司的代号,取区间[i,j]的寿司收益是d[i,j]和所有子区间的d,吃了c(c>0)种代号x的寿司的代价是mx^2+cx,给 ...

  2. 【BZOJ】2599: [IOI2011]Race 点分治

    [题意]给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000.注意点从0开始编号,无解输出-1. [算法]点分治 [题解] ...

  3. 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

    [题目]D. Best Edge Weight [题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1&l ...

  4. 第一周 ch01 课下测试

    1.Amdahl定律说明,我们对系统的某个部分做出重大改进,可以显著获得一个系统的加速比.(B) A .正确 B .错误 解析:Amdahl定律,该定律的主要思想是,当我们对系统的某个部分加速时,其对 ...

  5. HDU 1394 Minimum Inversion Number (树状数组)

    题目链接 Problem Description The inversion number of a given number sequence a1, a2, ..., an is the numb ...

  6. 使用Sass预定义一些常用的样式,非常方便

    CSS预处理技术现在已经非常成熟,比较流行的有Less,Sass,Stylus,在开发过程中提升我们的工作效率,缩短开发时间,方便管理和维护代码,可以根据自己的喜好选择一款自己喜欢的工具开发,使用很接 ...

  7. Mysql储存过程2:变量定义与参数传递

    #储存过程 中的变量定义 declare 变量名 类型 可选类型 -- 跟建表差不多 create procedure p() begin ); ; select age+number; end$ / ...

  8. 选择问题(选择数组中第K小的数)

    由排序问题可以引申出选择问题,选择问题就是选择并返回数组中第k小的数,如果把数组全部排好序,在返回第k小的数,也能正确返回,但是这无疑做了很多无用功,由上篇博客中提到的快速排序,稍稍修改下就可以以较小 ...

  9. VI编辑,配置文件

    1,VI编辑 vi 分为3种模式 1>一般模式: [Ctrl + f  ]         下一页 [Ctrl + b ]         上一页 [n+ enter]  向下移动n行 eg:2 ...

  10. Python 库汇总中文版

    这又是一个 Awesome XXX 系列的资源整理,由 vinta 发起和维护.内容包括:Web框架.网络爬虫.网络内容提取.模板引擎.数据库.数据可视化.图片处理.文本处理.自然语言处理.机器学习. ...