【noip模拟】连环

【题目描述】

惠子说:“连环可解也”。
这说明他是一个破解机关的高手,连连环都能解开,鲁班锁什么的自然不在话下。一位
鲁班的后人非常不服气,于是找到惠子,给他出了一道题。
他首先给了惠子一个长度为 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 + 5;
typedef long long ll;
int C, n, m, k, nxt[105], revNxt[105], lens, lent;
ll pre[N], preCnt[N], last[N], lastCnt[N];
ll tpre[105][N], tlast[105][N];
char s[N], t[105], revt[105], revs[N];

inline int read(){
    int i = 0, f = 1; char ch = getchar();
    for(; (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘; ch = getchar());
    if(ch == ‘-‘) f = -1, ch = getchar();
    for(; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar())
        i = (i << 3) + (i << 1) + (ch - ‘0‘);
    return i * f;
}

inline void wr(ll x){
    if(x < 0) putchar(‘-‘), x = -x;
    if(x > 9) wr(x / 10);
    putchar(x % 10 + ‘0‘);
}

inline void get_t_nxt(){
    for(int i = 2, j = 0; i <= lent; i++){
        while(j && t[j + 1] != t[i]) j = nxt[j];
        if(t[j + 1] == t[i]) j++;
        nxt[i] = j;
    }
}

inline void get_r_pre(){
    for(int i = 1, j = 0; i <= lens; i++){
        pre[i] = pre[i - 1];
        preCnt[i] = preCnt[i - 1];
        while(j && s[i] != t[j + 1]) j = nxt[j];
        if(s[i] == t[j + 1]) j++;
        if(j == lent){
            pre[i] += i;
            preCnt[i]++;
            j = nxt[j];
        }
    }
}

inline void get_t_rev_nxt(){
    for(int i = 2, j = 0; i <= lent; i++){
        while(j && revt[j + 1] != revt[i]) j = revNxt[j];
        if(revt[j + 1] == revt[i]) j++;
        revNxt[i] = j;
    }
}

inline void get_l_last(){
    for(int i = 1, j = 0; i <= lens; i++){
        last[i] = last[i - 1];
        lastCnt[i] = lastCnt[i - 1];
        while(j && revs[i] != revt[j + 1]) j = revNxt[j];
        if(revs[i] == revt[j + 1]) j++;
        if(j == lent){
            last[i] += n - i + 1;
            lastCnt[i]++;
            j = revNxt[j];
        }
    }
}

inline void get_t_pre(){
    for(int i = 1; i <= lent; i++){
        char now[105];
        int now_nxt[105] = {0};
        for(int j = 1; j <= i; j++)
            now[j] = t[j];
        for(int k = 2, l = 0; k <= i; k++){
            while(l && now[l + 1] != now[k]) l = now_nxt[l];
            if(now[l + 1] == now[k]) l++;
            now_nxt[k] = l;
        }
        for(int k = 1, l = 0; k <= lens; k++){
            tpre[i][k] = tpre[i][k - 1];
            while(l && now[l + 1] != s[k]) l = now_nxt[l];
            if(now[l + 1] == s[k]) l++;
            if(l == i){
                tpre[i][k]++;
                l = now_nxt[l];
            }
        }
    }
}

inline void get_t_last(){
    for(int i = 1; i <= lent; i++){
        char now[105];
        int now_nxt[105] = {0};
        for(int j = 1; j <= i; j++)
            now[j] = revt[j];
        for(int k = 2, l = 0; k <= i; k++){
            while(l && now[l + 1] != now[k]) l = now_nxt[l];
            if(now[l + 1] == now[k]) l++;
            now_nxt[k] = l;
        }
        for(int k = 1, l = 0; k <= lens; k++){
            tlast[i][k] = tlast[i][k - 1];
            while(l && now[l + 1] != revs[k]) l = now_nxt[l];
            if(now[l + 1] == 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 + 1);
        scanf("%s", t + 1);
        memcpy(revt, t, sizeof t);
        memcpy(revs, s, sizeof s);
        reverse(revt + 1, revt + m + 1);
        reverse(revs + 1, revs + n + 1);
        lent = m;
        lens = n;
        memset(nxt, 0, sizeof nxt);
        memset(revNxt, 0, sizeof revNxt);
        memset(pre, 0, sizeof pre);
        memset(last, 0, sizeof last);
        memset(tpre, 0, sizeof tpre);
        memset(tlast, 0, sizeof tlast);
        memset(preCnt, 0, sizeof preCnt);
        memset(lastCnt, 0, 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 = 0;
            ans += preCnt[L] * (L + 1) * (n - R + 1);
            ans -= (n - R + 1) * pre[L];
            ans -= lastCnt[n - R + 1] * (R - 1) * L;
            ans += last[n - R + 1] * L;
            for(int i = 1; i <= lent; i++)
                ans += tpre[i][L] * tlast[lent - (i + 1) + 1][n - R + 1];
            wr(ans), putchar(‘\n‘);
        }
    }
}
时间: 2024-10-15 18:43:19

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

NOIP模拟17.8.17

NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的.全由小写英文字母构成的字符串,只能使用 k 种字母.要求满足:• 字符串中相邻的两个字母不能相同.• 必须出现恰好 k 种不同的字母.这样的合法字符串可能有很多,小 L 让小 G 输出字典序最小的那个.小 G 太笨啦,不会做这道题,希望你帮帮他.[输入格

[BZOJ入门OJ2092][Noip模拟题]舞会

2092: [Noip模拟题]舞会 Time Limit: 20 Sec  Memory Limit: 256 MB Submit: 9  Solved: 5 [Submit][Status][Web Board] Description 学校举行舞会啦,一共有N个人参加,所有人站成一排,从左开始编号,最左边的人编号为1 ,最右边的为N.每个人跳舞的熟练度我们用一个整数表示,第i个人的熟练度为Ai,每次熟 练度最接近的一对相邻男女会出列跳舞,如果有多对那么最左边的那一对会先出列,请你给 出出列跳

【简单思考】noip模拟赛 NTR酋长

NTR酋长 (ntr.pas/.c/.cpp) 黄巨大终于如愿以偿的进入了czy的后宫中……但是czy很生气……他要在黄巨大走到他面前的必经之路上放上几个NTR酋长来阻挡黄巨大. 众所周知,NTR酋长有一个技能是沟壑(F).它会在地图上产生一条长长的障碍物阻挡人前进.Czy打算在一个n*m的矩形(必经之路?)中放上NTR酋长.NTR酋长要一个一个放下去,而且每放一个都会向四角倾斜的方向放出无限长的沟壑,而已经被沟壑挡住的地方就不能再放NTR酋长了. 请注意:不会出现沟壑的路径挡住另一个沟壑的情况

【noip模拟赛】 射击

这题似乎是什么安阳一中的模拟题,不管了,反正是学长出的noip模拟赛里面的题目.... 射击(shoot.pas/.c/.cpp) 时间限制:1s,内存限制128MB 题目描述: 据史书记载,对越反击战时期,有位中国侦察兵,他的代号叫814.一天他执行狙击任务,他的任务地区是n座恰巧在一条直线上的山.这些山所在直线恰巧为东西走向,山从东到西依次编号为1~n.一天814隐藏在编号为k的山上,每座山上都有1个目标. 814也非常的厉害,任务结束时杀了很多人,可是史书中只记载了两点: 1:814一定攻

NOIP模拟赛

#1[Nescafé 31]杯NOIP模拟赛 t1 题意:n*m的棋盘上从(1,1)走到(n,m),只能向下或向右,一些格子有老鼠,每个老鼠互不相同,当处于与老鼠有重边的格子时,视为看见了这只老鼠,求到终点看到最少的不同老鼠数. 分析:DP 由于求得是看到的不同的老鼠数目,不能直接用过河卒做,因为同一个位置的老鼠可能会统计多次,我们还需要增加一维即方向. f[i,j,0]表示到从上面一个格子走到(i,j)时最少老鼠数,f[i,j,1]表示左边. f[i,j,0]:=min(f[i-1,j,0]+

NOIP模拟 17.8.18

NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也需要一定量的草作为饲料对于第 i头奶牛来说,它每天可以产 vi升的奶,同时需要 wi千克的草作为饲料现在来自蚯蚓国的九条可怜想借一些奶牛,使借走的这些奶牛每天的总产奶量最大,但九条可怜很穷,每天最多只能提供W千克的草作为饲料,而且她还需要对付跳蚤国的神刀手,所以她把这个问题交给了阿强巴,不不不……阿

NOIP模拟 6.28

NOIP模拟赛6.28 Problem 1 高级打字机(type.cpp/c/pas) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x.(type操作) 2.U x:撤销最后的x次修改操作.(Undo操作) (注意Query操作并不算修改操作) 3.Q x:询问当前文章中第x个字母并输出.(Query操作) 文章一开始可以视为空串. [输入格式]

NOIP模拟17.9.21

NOIP模拟17.9.21 1 任务安排manage.in/.out/.cpp1.1 问题描述你有N 个工作,同一时刻只能做一个任务, 其中每个工作有其所需时间, 及完成的Deadline(截止时间), 问要完成所有工作, 最迟要从什么时候开始.你最早可以从时间0 开始工作.1.2 输入格式第一行一个整数N,表示任务数量接下来n 行,每行两个整数,Ti; Si,分别表示该任务的持续时间和截止时间.1.3 输出格式输出一个整数,表示最晚的开始时间,如果不能完成,输出-1.1.4 样例输入43 58

NOIP模拟赛 6.29

2017-6-29 NOIP模拟赛 Problem 1 机器人(robot.cpp/c/pas) [题目描述] 早苗入手了最新的Gundam模型.最新款自然有着与以往不同的功能,那就是它能够自动行走,厉害吧. 早苗的新模型可以按照输入的命令进行移动,命令包括‘E’.‘S’.‘W’.‘N’四种,分别对应东南西北.执行某个命令时,它会向对应方向移动一个单位.作为新型机器人,它可以执行命令串.对于输入的命令串,每一秒它会按命令行动一次.执行完命令串的最后一个命令后,会自动从头开始循环.在0时刻时机器人

NOIP模拟17.9.22

NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥ ??的位置去,但很不幸数轴上有??个区间是禁区,不能进入.青蛙会选择一个长度??,从原点开始每次向右跳长度为??的一段.一路上青蛙会停的位置是0, ??, 2??,…直到跳到了≥ ??的位置,任意一个位置都不能在禁区中.请求出??的最小值,注意??可以是实数.[输入格式]输入文件为susume.in.输入文件的第一行包含两个整数??和??,含义如问题描述中所述.接下来??行,每行描述一个禁区.每行有两个整数