Hdu6068 Classic Quotation(2017多校第4场)

xiaoxiao2021-02-28  82

Classic Quotation

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others) Total Submission(s): 416    Accepted Submission(s): 139 Problem Description When online chatting, we can save what somebody said to form his ''Classic Quotation''. Little Q does this, too. What's more? He even changes the original words. Formally, we can assume what somebody said as a string  S  whose length is  n . He will choose a continuous substring of  S (or choose nothing), and remove it, then merge the remain parts into a complete one without changing order, marked as  S . For example, he might remove ''not'' from the string ''I am not SB.'', so that the new string  S  will be ''I am SB.'', which makes it funnier. After doing lots of such things, Little Q finds out that string  T  occurs as a continuous substring of  S  very often. Now given strings  S  and  T , Little Q has  k  questions. Each question is, given  L  and  R , Little Q will remove a substring so that the remain parts are  S[1..i]  and  S[j..n] , what is the expected times that  T  occurs as a continuous substring of  S  if he choose every possible pair of  (i,j)(1iL,Rjn)  equiprobably? Your task is to find the answer  E , and report  E×L×(nR+1)  to him. Note : When counting occurrences,  T  can overlap with each other.   Input The first line of the input contains an integer  C(1C15) , denoting the number of test cases. In each test case, there are  3  integers  n,m,k(1n50000,1m100,1k50000)  in the first line, denoting the length of  S , the length of  T  and the number of questions. In the next line, there is a string  S  consists of  n  lower-case English letters. Then in the next line, there is a string  T  consists of  m  lower-case English letters. In the following  k  lines, there are  2  integers  L,R(1L<Rn)  in each line, denoting a question.   Output For each question, print a single line containing an integer, denoting the answer.   Sample Input 1 8 5 4 iamnotsb iamsb 4 7 3 7 3 8 2 7   Sample Output 1 1 0 0   Source 2017 Multi-University Training Contest - Team 4 ———————————————————————————————————— 题目的意思是是给出两个字符串s,t,求s字符串截取[1,i][j,n] (1<=i<=l,r<=j<=n)后有多少个子串t; 思路:先贴一下官方题解:

首先通过KMP算法预处理出TTnextnext数组,设:

pref_iprefi表示SS的前缀iiTT进行KMP后KMP的指针到达了哪里。

preg_ipregi表示SS的前缀iiTT出现的次数。

suf_{i,j}sufi,j表示从SS的后缀ii,从jj指针开始KMP,能匹配多少个TT

那么前缀ii拼接上后缀jjTT的个数为preg_i+suf_{j,pref_i}pregi+sufj,prefi

pregpregpregpreg的前缀和,sufsufsufsuf的后缀和,s_{i,j}si,j表示ii前面中prefprefjj的个数,那么对于询问L,RL,R

ans=\sum_{i=1}^L\sum_{j=R}^n preg_i+suf_{j,pref_i}=(n-R+1)preg_L+\sum_{i=0}^{m-1}s_{L,i}\times suf_{R,i}ans=i=1Lj=Rnpregi+sufj,prefi=(nR+1)pregL+i=0m1sL,i×sufR,i

以上所有数组均可以使用KMP和递推求出,时间复杂度O((n+k)m)O((n+k)m)

s数组可以在kmp时预处理出来,suf可以通过预处理递推出来,枚举t字符串每一位和a-z匹配算出新的next数组,用dp的方式预处理出suf

具体看代码:

#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <queue> #include <vector> #include <bitset> using namespace std; #define LL long long const int INF = 0x3f3f3f3f; #define mod 10000007 #define mem(a,b) memset(a,b,sizeof a) char s[50005],t[505]; int nt[505],pren[50005],suf[50005][505],sx[50005][505],mat[505][505],nt2[505][505]; void get_next(int x) { nt[0]=0; nt[1]=0; for(int i=2; i<=x; i++) { int k=nt[i-1]; while(k>0&&t[i]!=t[k+1]) k=nt[k]; nt[i]=t[i]==t[k+1]?k+1:0; } } int main() { int m,n,q,T; for(scanf("%d",&T); T--;) { scanf("%d%d%d",&n,&m,&q); scanf("%s%s",s+1,t+1); get_next(m); memset(sx,0,sizeof sx); memset(pren,0,sizeof pren); for(int i=1,j=0; i<=n; i++) { while(j&&s[i]!=t[j+1]) j=nt[j]; if(s[i]==t[j+1]) j++; pren[i]=pren[i-1]; if(j==m) pren[i]++,j=nt[j]; for(int kk=0; kk<m; kk++) sx[i][kk]=sx[i-1][kk]; sx[i][j]++; } for(int i=1; i<=n; i++) pren[i]+=pren[i-1]; memset(mat,0,sizeof mat); for(int i=0; i<m; i++) for(int j='a'; j<='z'; j++) { int k=i; while(k&&t[k+1]!=j) k=nt[k]; if(t[k+1]==j) k++; if(k==m) k=nt[k],mat[i][j]=1; nt2[i][j]=k; } memset(suf,0,sizeof suf); for(int i=n; i>0; i--) { for(int j=0; j<m; j++) suf[i][j]=mat[j][s[i]]+suf[i+1][nt2[j][s[i]]]; } for(int i=n; i>0; i--) { for(int j=0; j<m; j++) suf[i][j]+=suf[i+1][j]; } while(q--) { int l,r; scanf("%d%d",&l,&r); LL ans=1LL*(n-r+1)*pren[l]; for(int i=0; i<m; i++) { ans+=1LL*sx[l][i]*suf[r][i]; } printf("%lld\n",ans); } } return 0; }

转载请注明原文地址: https://www.6miu.com/read-68276.html

最新回复(0)