给定一个由且仅由字符$'H','T'$构成的字符串$S$

给定一个最初为空的字符串$T$,每次随机地在$T$的末尾添加$'H'$或者$'T'$

问当$S$为$T$的后缀时,在末尾添加字符的期望次数

妙啊!

设$f_i(0\leq i \leq n-1)$表示(在$T$的末尾匹配$S_{1\cdots i}$)到(在$T$的末尾匹配$S_{1\cdots i+1}$)期望添加多少个字符

①有$\frac12$的概率直接匹配,需要添加$1$个字符

②另外$\frac12$的概率失配,需要添加更多字符

我们来看看②,为了解决问题,我们引入$go_{i,j}(0\leq i\leq n-1,j\in\{'H','T'\})$表示当已经在$T$的末尾匹配$S_{1\cdots i}$时在$T$的末尾添加字符$j$能匹配到的最远位置

首先假设我们计算好了$go_{1\cdots i-1,'H'\cdots'T'}$,想计算$go_{i,'H'\cdots'T'}$

若$S_{i+1}='H'$,则$go_{i,'H'}=i+1$,$go_{i,'T'}=go_{next_i,'T'}$

若$S_{i+1}='T'$,则$go_{i,'H'}=go_{next_i,'H'}$,$go_{i,'T'}=i+1$

其中$next_i$代表最大的$k\lt i$使得$S_{1\cdots k}=S_{i-k+1\cdots i}$,与kmp中的$next$含义相同

有了$go_{i,j}$,我们现在可以解决②了

失配之后用$go_{i,j}$找到再次匹配的位置,然后一路添加字符直到到达$S_{i+1}$

若$S_{i+1}='H'$,则$f_i=\frac12+\frac12(1+\sum\limits_{go_{i,'T'}\leq j\leq i}f_j)$

整理得$f_i=2+\sum\limits_{go_{i,'T'}\leq j\leq i-1}f_j$

若$S_{i+1}='T'$,则$f_i=\frac12+\frac12(1+\sum\limits_{go_{i,'H'}\leq j\leq i}f_j)$

整理得$f_i=2+\sum\limits_{go_{i,'H'}\leq j\leq i-1}f_j$

综上,我们先用kmp预处理出$next_i$,然后用$next_i$预处理出$go_{i,j}$,最后用$go_{i,j}$算出$f_i$

递推中的$\sum$边算边累加即可,最后的答案为$f_0+f_1+\cdots+f_{n-1}$

#include<stdio.h>
#include<string.h>
#define mod 1000000007
char s[1000010];
int pi[1000010],f[1000010],sumf[1000010],go[1000010][2],n,i,j;
int main(){
	scanf("%s",s+1);
	n=strlen(s+1);
	pi[1]=0;
	j=0;
	for(i=2;i<=n;i++){
		while(j&&s[i]!=s[j+1])j=pi[j];
		if(s[i]==s[j+1])j++;
		pi[i]=j;
	}
	//0:H 1:T
	for(i=0;i<n;i++){
		if(s[i+1]=='H'){
			go[i][0]=i+1;
			go[i][1]=go[pi[i]][1];
		}else{
			go[i][0]=go[pi[i]][0];
			go[i][1]=i+1;
		}
	}
	f[0]=2;
	sumf[0]=2;
	for(i=1;i<n;i++){
		if(s[i+1]=='H')
			f[i]=(2+sumf[i-1]-(go[i][1]?sumf[go[i][1]-1]:0))%mod;
		else
			f[i]=(2+sumf[i-1]-(go[i][0]?sumf[go[i][0]-1]:0))%mod;
		sumf[i]=(sumf[i-1]+f[i])%mod;
	}
	printf("%d",(sumf[n-1]+mod)%mod);
}

[Contest20170910]string的更多相关文章

  1. 透过WinDBG的视角看String

    摘要 : 最近在博客园里面看到有人在讨论 C# String的一些特性. 大部分情况下是从CODING的角度来讨论String. 本人觉得非常好奇, 在运行时态, String是如何与这些特性联系上的 ...

  2. JavaScript String对象

    本编主要介绍String 字符串对象. 目录 1. 介绍:阐述 String 对象的说明以及定义方式. 2. 实例属性:介绍 String 对象的实例属性: length. 3. 实例方法:介绍 St ...

  3. ElasticSearch 5学习(9)——映射和分析(string类型废弃)

    在ElasticSearch中,存入文档的内容类似于传统数据每个字段一样,都会有一个指定的属性,为了能够把日期字段处理成日期,把数字字段处理成数字,把字符串字段处理成字符串值,Elasticsearc ...

  4. [C#] string 与 String,大 S 与小 S 之间没有什么不可言说的秘密

    string 与 String,大 S 与小 S 之间没有什么不可言说的秘密 目录 小写 string 与大写 String 声明与初始化 string string 的不可变性 正则 string ...

  5. js报错: Uncaught RangeError: Invalid string length

    在ajax请求后得到的json数据,遍历的时候chrome控制台报这个错误:Uncaught RangeError: Invalid string length,在stackoverflow查找答案时 ...

  6. c# 字符串连接使用“+”和string.format格式化两种方式

    参考文章:http://www.liangshunet.com/ca/201303/218815742.htm 字符串之间的连接常用的两种是:“+”连接.string.format格式化连接.Stri ...

  7. 【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed

    之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码: //将字符串"a"写入流,再拿到流的 ...

  8. JavaScript中String对象的方法介绍

    1.字符方法 1.1 charAt() 方法,返回字符串中指定位置的字符. var question = "Do you like JavaScript?"; alert(ques ...

  9. 在多线程编程中lock(string){...}隐藏的机关

    常见误用场景:在订单支付环节中,为了防止用户不小心多次点击支付按钮而导致的订单重复支付问题,我们用 lock(订单号) 来保证对该订单的操作同时只允许一个线程执行. 这样的想法很好,至少比 lock( ...

随机推荐

  1. Git 常用命令(二)

    用 git init 在目录中创建新的 Git 仓库.  $ mkdir test $ cd test/ $ git init Initialized empty Git repository in ...

  2. Bower A package manager for the web

    Bower can manage components that contain HTML, CSS, JavaScript, fonts or even image files. Bower doe ...

  3. Eureka服务续约(Renew)源码分析

    主要对Eureka的Renew(服务续约),从服务提供者发起续约请求开始分析,通过阅读源码和画时序图的方式,展示Eureka服务续约的整个生命周期.服务续约主要是把服务续约的信息更新到自身的Eurek ...

  4. ES6新增的let与const

    1.const 声明常量,一旦声明必须立马赋值,否则报错 const PI = 3.14 const PI; //报错:Uncaught SyntaxError: Missing initialize ...

  5. ie8下a标签中的图片出现边框

    1.ie8下a标签中的图片出现边框 <a href="#"><img src="horse.jpg"></a> 效果如图所示 ...

  6. perl6中的替换

    use v6; =begin pod perl6 中的替换用S/// S有几个可选参数: :g —(长形式::global)全局匹配:替换掉所有的出现 :i —不区分大小写的匹配 :ii —(长形式: ...

  7. peepscan前期准备工作

    具有的功能 1.whoami 2.sub doamin https://dns.aizhan.com/huayi-faucet.com/ 3.dir scan 4.web server 5.port ...

  8. C++学习之路(八):关于C++提供的强制类型转换

    C语言中提供了旧式的强制类型转换方法.比如: int a  =1; char *p = (char *)&a; 上述将a的地址单元强制转换为char类型的指针.这里暂且不说上述转换结果是否合理 ...

  9. rdpClient

    https://github.com/jean343/RPI-GPU-rdpClient https://github.com/Nullstr1ng/MultiRDPClient.NET https: ...

  10. Educational Codeforces Round 26 F. Prefix Sums 二分,组合数

    题目链接:http://codeforces.com/contest/837/problem/F 题意:如题QAQ 解法:参考题解博客:http://www.cnblogs.com/FxxL/p/72 ...