【题目描述】

惠子说:“连环可解也”。
这说明他是一个破解机关的高手,连连环都能解开,鲁班锁什么的自然不在话下。一位
鲁班的后人非常不服气,于是找到惠子,给他出了一道题。
他首先给了惠子一个长度为 n的字符串s和一个长度为 m 的字符串 t,现在,他有 k 个
询问,每个询问是给出两个整数 L,R,询问任选一对(i,j)满足 1≤i≤L,n≥j≥R,删去 s 的
[i+1,j−1]这个区间的子串,剩下两块拼在一起,求t 在其中的匹配数的期望 e。
惠子非常擅长吹逼,但是对数学却搞不太明白,于是他请你来帮他。
为了防止实数的精度误差,你只需要输出 e×L×(n−R+1)

【输入格式】

第一行一个整数 C,表示数据组数
每组数据,第一行是三个整数n,m,k
接下来一行字符串表示 s
接下来一行字符串表示 t
接下里 k 行,每行两个整数 Li,Ri,表示一组询问
C≤5
n≤5×10^4,m≤100,k≤5×10^4
1≤Li<Ri-1≤n
对于30%的数据,n≤100,k≤100

【输出格式】

对于每组询问,输出一行一个整数表示答案

【样例输入】

1
8 5 4
iamnotsb
iamsb
4 7
3 7
3 8
2 7

【样例输出】

1
1
0
0

【题目分析】

删去一段之后的匹配分两种,一种是本来就匹配的,删除没有影响他,另一种是本来不匹配,删除之后因为两端连接产生的新匹配。

首先考虑第一种:设t的某个匹配为(l,r),推一下公式发现若r≤L,那么这个匹配的贡献为(L−r+1)×(n−R+1)=(L+1)(n−R+1)−r(n−R+1),那么我们可以预处理一下匹配的r的前缀和匹配数的前缀和,就可以O(1)询问出来了。而若l≥R,那么贡献是(l−R+1)×L,也类似的弄两个前缀和出来就好。

现在考虑因为删除中间一坨而产生的新匹配,我们考虑把t拆开成两个非空部分t1,t2,显然这一种的总贡献等同于t1在[1,L]内的匹配数乘以t2在[R,n]内的匹配数,这个也可以预处理一下前缀和,询问的时候枚举拆开的位置就行了。

【code】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std; const int N = 5e4 + ;
typedef long long ll;
int C, n, m, k, nxt[], revNxt[], lens, lent;
ll pre[N], preCnt[N], last[N], lastCnt[N];
ll tpre[][N], tlast[][N];
char s[N], t[], revt[], revs[N]; inline int read(){
int i = , f = ; char ch = getchar();
for(; (ch < '' || ch > '') && ch != '-'; ch = getchar());
if(ch == '-') f = -, ch = getchar();
for(; ch >= '' && ch <= ''; ch = getchar())
i = (i << ) + (i << ) + (ch - '');
return i * f;
} inline void wr(ll x){
if(x < ) putchar('-'), x = -x;
if(x > ) wr(x / );
putchar(x % + '');
} inline void get_t_nxt(){
for(int i = , j = ; i <= lent; i++){
while(j && t[j + ] != t[i]) j = nxt[j];
if(t[j + ] == t[i]) j++;
nxt[i] = j;
}
} inline void get_r_pre(){
for(int i = , j = ; i <= lens; i++){
pre[i] = pre[i - ];
preCnt[i] = preCnt[i - ];
while(j && s[i] != t[j + ]) j = nxt[j];
if(s[i] == t[j + ]) j++;
if(j == lent){
pre[i] += i;
preCnt[i]++;
j = nxt[j];
}
}
} inline void get_t_rev_nxt(){
for(int i = , j = ; i <= lent; i++){
while(j && revt[j + ] != revt[i]) j = revNxt[j];
if(revt[j + ] == revt[i]) j++;
revNxt[i] = j;
}
} inline void get_l_last(){
for(int i = , j = ; i <= lens; i++){
last[i] = last[i - ];
lastCnt[i] = lastCnt[i - ];
while(j && revs[i] != revt[j + ]) j = revNxt[j];
if(revs[i] == revt[j + ]) j++;
if(j == lent){
last[i] += n - i + ;
lastCnt[i]++;
j = revNxt[j];
}
}
} inline void get_t_pre(){
for(int i = ; i <= lent; i++){
char now[];
int now_nxt[] = {};
for(int j = ; j <= i; j++)
now[j] = t[j];
for(int k = , l = ; k <= i; k++){
while(l && now[l + ] != now[k]) l = now_nxt[l];
if(now[l + ] == now[k]) l++;
now_nxt[k] = l;
}
for(int k = , l = ; k <= lens; k++){
tpre[i][k] = tpre[i][k - ];
while(l && now[l + ] != s[k]) l = now_nxt[l];
if(now[l + ] == s[k]) l++;
if(l == i){
tpre[i][k]++;
l = now_nxt[l];
}
}
}
} inline void get_t_last(){
for(int i = ; i <= lent; i++){
char now[];
int now_nxt[] = {};
for(int j = ; j <= i; j++)
now[j] = revt[j];
for(int k = , l = ; k <= i; k++){
while(l && now[l + ] != now[k]) l = now_nxt[l];
if(now[l + ] == now[k]) l++;
now_nxt[k] = l;
}
for(int k = , l = ; k <= lens; k++){
tlast[i][k] = tlast[i][k - ];
while(l && now[l + ] != revs[k]) l = now_nxt[l];
if(now[l + ] == revs[k]) l++;
if(l == i){
tlast[i][k]++;
l = now_nxt[l];
}
}
}
} int main(){
freopen("lianhuan.in","r",stdin);
freopen("lianhuan.out","w",stdout);
C = read();
while(C--){
n = read(), m = read(), k = read();
scanf("%s", s + );
scanf("%s", t + );
memcpy(revt, t, sizeof t);
memcpy(revs, s, sizeof s);
reverse(revt + , revt + m + );
reverse(revs + , revs + n + );
lent = m;
lens = n;
memset(nxt, , sizeof nxt);
memset(revNxt, , sizeof revNxt);
memset(pre, , sizeof pre);
memset(last, , sizeof last);
memset(tpre, , sizeof tpre);
memset(tlast, , sizeof tlast);
memset(preCnt, , sizeof preCnt);
memset(lastCnt, , sizeof lastCnt);
get_t_nxt();
get_t_rev_nxt();
get_r_pre();
get_l_last();
get_t_pre();
get_t_last();
while(k--){
int L = read(), R = read();
ll ans = ;
ans += preCnt[L] * (L + ) * (n - R + );
ans -= (n - R + ) * pre[L];
ans -= lastCnt[n - R + ] * (R - ) * L;
ans += last[n - R + ] * L;
for(int i = ; i <= lent; i++)
ans += tpre[i][L] * tlast[lent - (i + ) + ][n - R + ];
wr(ans), putchar('\n');
}
}
}

【noip模拟】连环的更多相关文章

  1. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  2. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  3. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  4. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  5. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  6. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  7. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  8. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  9. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

  10. CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

    A.二叉树的的根 题目:http://www.contesthunter.org/contest/CH%20Round%20%2349%20-%20Streaming%20%234%20(NOIP 模 ...

随机推荐

  1. 使用Invoke解决多线程间的控件访问出错

    // 按钮点击事件处理程序private void button1_Click(object sender, EventArgs e){    //创建新线程    Thread processorT ...

  2. Android中的Parcelable接口和Serializable使用方法和差别

    Parcelable接口: Interface for classes whose instances can be written to and restored from a Parcel. Cl ...

  3. C++组合数(combination)的实现

    实现: (nm) 既需要计算组合的总数 (32)=3: 也需要分别获得每一种组合的情形,用于穷举搜索: 1, 2; 1, 3; 2, 3 1. 递归实现 // picked + toPick == m ...

  4. autohotkey 自动登录输入用户名密码 getElementsByTagName/getElementsByClassName/getElementById

    针对button未设置id的.可以通过getElementsByTagName获取button的对象数组,再明确其在对象数组中的位置,如第4个button,通过[3]获取.再调用此对象的click() ...

  5. 8.6 Android灯光系统_源码分析_背光灯

    Change system screen brightness, using android.provider.Settings.System.SCREEN_BRIGHTNESSandroid-er. ...

  6. Linux下交叉编译gdb,gdbserver+gdb的使用以及通过gdb调试core文件

    交叉编译gdb和gdbserver 1.下载gdb:下载地址为:http://ftp.gnu.org/gnu/gdb/按照一般的想法,最新版本越好,因此下载7.2这个版本.当然,凡事无绝对.我们以gd ...

  7. angular内置指令相关知识

    原文地址 https://www.jianshu.com/p/5a5b43a8e91f 大纲 1.angular指令的分类 2.angular指令之——组件 3.angular指令之——属性指令 (n ...

  8. SpringMVC上传图片总结(1)---常规方法进行图片上传,使用了MultipartFile、MultipartHttpServletRequest

    原文地址:https://blog.csdn.net/chenchunlin526/article/details/70945877 SpringMVC上传图片总结(1)---常规方法进行图片上传,使 ...

  9. Linux系统编程——线程私有数据

    在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...

  10. Hadoop文件的基本操作 分类: A1_HADOOP 2014-12-05 11:36 392人阅读 评论(0) 收藏

    Hadoop提供了大量的API对文件系统中的文件进行操作,主要包括: (1)读取文件 (2)写文件 (3)读取文件属性 (4)列出文件 (5)删除文件 1、读取文件 以下示例中,将hdfs中的一个文件 ...