hdu 1711 && Codeforces Round #344 (Div. 2) D 【KMP】

来源:互联网 发布:个人工作备忘录软件 编辑:程序博客网 时间:2024/05/16 16:05




链接:戳这里


Number Sequence


Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 18633    Accepted Submission(s): 8073




Problem Description
Given two sequences of numbers : a[1], a[2], ...... , a[N], and b[1], b[2], ...... , b[M] (1 <= M <= 10000, 1 <= N <= 1000000). Your task is to find a number K which make a[K] = b[1], a[K + 1] = b[2], ...... , a[K + M - 1] = b[M]. If there are more than one K exist, output the smallest one.
 

Input
The first line of input is a number T which indicate the number of cases. Each case contains three lines. The first line is two numbers N and M (1 <= M <= 10000, 1 <= N <= 1000000). The second line contains N integers which indicate a[1], a[2], ...... , a[N]. The third line contains M integers which indicate b[1], b[2], ...... , b[M]. All integers are in the range of [-1000000, 1000000].
 
Output
For each test case, you should output one line which only contain K described above. If no such K exists, output -1 instead.
 

Sample Input
2
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 1 3
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 2 1


Sample Output
6
-1


Source
HDU 2007-Spring Programming Contest


题意:裸地KMP,只是为了再熟悉一下KMP的过程,方便写cf344的D题,模仿大白书上的思路拍的


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<vector>#include <ctime>#include<queue>#include<set>#include<map>#include<stack>#include<cmath>#define mst(ss,b) memset((ss),(b),sizeof(ss))#define maxn 0x3f3f3f3f#define MAX 1000100///#pragma comment(linker, "/STACK:102400000,102400000")typedef long long ll;typedef unsigned long long ull;#define INF (1ll<<60)-1using namespace std;int T;int s[1000100],p[1000100];int f[1000100];int n,m;void getf(){    int j=0;    f[0]=0;    f[1]=0;    for(int i=1;i<m;i++){        j=f[i];        if(j && p[i]!=p[j]) j=f[j];        if(p[i]==p[j]) f[i+1]=j+1;        else f[i+1]=0;    }}int KMP(){    int j=0;    for(int i=0;i<n;i++){        if(j && s[i]!=p[j]) j=f[j];        if(s[i]==p[j]) j++;        if(j==m) return i-m+2;    }    return -1;}int main(){    scanf("%d",&T);    while(T--){        mst(f,0);        scanf("%d%d",&n,&m);        for(int i=0;i<n;i++) scanf("%d",&s[i]);        for(int i=0;i<m;i++) scanf("%d",&p[i]);        getf();        printf("%d\n",KMP());    }    return 0;}



链接:戳这里



D. Messenger
time limit per test2 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
Each employee of the "Blake Techologies" company uses a special messaging app "Blake Messenger". All the stuff likes this app and uses it constantly. However, some important futures are missing. For example, many users want to be able to search through the message history. It was already announced that the new feature will appear in the nearest update, when developers faced some troubles that only you may help them to solve.

All the messages are represented as a strings consisting of only lowercase English letters. In order to reduce the network load strings are represented in the special compressed form. Compression algorithm works as follows: string is represented as a concatenation of n blocks, each block containing only equal characters. One block may be described as a pair (li, ci), where li is the length of the i-th block and ci is the corresponding letter. Thus, the string s may be written as the sequence of pairs .

Your task is to write the program, that given two compressed string t and s finds all occurrences of s in t. Developers know that there may be many such occurrences, so they only ask you to find the number of them. Note that p is the starting position of some occurrence of s in t if and only if tptp + 1...tp + |s| - 1 = s, where ti is the i-th character of string t.

Note that the way to represent the string in compressed form may not be unique. For example string "aaaa" may be given as , , ...

Input
The first line of the input contains two integers n and m (1 ≤ n, m ≤ 200 000) — the number of blocks in the strings t and s, respectively.

The second line contains the descriptions of n parts of string t in the format "li-ci" (1 ≤ li ≤ 1 000 000) — the length of the i-th part and the corresponding lowercase English letter.

The second line contains the descriptions of m parts of string s in the format "li-ci" (1 ≤ li ≤ 1 000 000) — the length of the i-th part and the corresponding lowercase English letter.

Output
Print a single integer — the number of occurrences of s in t.

Examples
input
5 3
3-a 2-b 4-c 3-a 2-c
2-a 2-b 1-c
output
1
input
6 1
3-a 6-b 7-a 4-c 8-e 2-a
3-a
output
6
input
5 5
1-h 1-e 1-l 1-l 1-o
1-w 1-o 1-r 1-l 1-d
output
0
Note
In the first sample, t = "aaabbccccaaacc", and string s = "aabbc". The only occurrence of string s in string t starts at position p = 2.

In the second sample, t = "aaabbbbbbaaaaaaacccceeeeeeeeaa", and s = "aaa". The occurrences of s in t start at positions p = 1, p = 10, p = 11, p = 12, p = 13 and p = 14.


题意:给出分别n,m(1<=n,m<=200000) ,n表示有n个"x整数-c字符"组成的串,表示连续的字符c有x个。m表示有m个"x整数-c字符"组成的串,表示连续的字符c有x个.

这里定义n个字符串铺开之后为s串,m个字符串铺开是p串,问p串在s串中出现了多少次(典型的kmp)


思路:与平常的kmp不同的是判断字符相等的时候还需要判断个数是否相等,其实也就是多了一个变量,我的kmp板子是模仿大白书上的,也就是i,j都是从0开始的,一开始这样写一直wa41,后来调试不出来就改板子i,j从1开始,然后就过了

这里需要分情况讨论:

1 当lp==1时,也就是直接暴力找过去就可以了

2 当lp==2时,直接暴力判断左右两边是否满足条件就是了

3 当lp==3时,需要kmp过程,写起来注意点细节就可以了,具体的解释在代码中


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<vector>#include <ctime>#include<queue>#include<set>#include<map>#include<stack>#include<cmath>#define mst(ss,b) memset((ss),(b),sizeof(ss))#define maxn 0x3f3f3f3f#define MAX 1000100///#pragma comment(linker, "/STACK:102400000,102400000")typedef long long ll;typedef unsigned long long ull;#define INF (1ll<<60)-1using namespace std;ll n,m;struct node{    char c;    ll v;}s[200020],p[200020];ll ans=0;int f[200020];int main(){    scanf("%I64d%I64d",&n,&m);    char c;    ll x;    int ls=0,lp=0;    for(int i=1;i<=n;i++){        scanf("%I64d-%c",&x,&c);        if(ls>0 && c==s[ls].c) s[ls].v+=x;        else s[++ls].v=x,s[ls].c=c;    }    for(int i=1;i<=m;i++){        scanf("%I64d-%c",&x,&c);        if(lp>0 && c==p[lp].c) p[lp].v+=x;        else p[++lp].v=x,p[lp].c=c;    }    if(lp==1){        for(int i=1;i<=ls;i++){            if(p[1].c==s[i].c && p[1].v<=s[i].v) ans+=s[i].v-p[1].v+1;        }    } else if(lp==2){        for(int i=1;i<ls;i++){            if(p[1].c==s[i].c && p[2].c==s[i+1].c && p[1].v<=s[i].v && p[2].v<=s[i+1].v)                ans++;        }    } else {        int j=2;        f[2]=f[3]=2;        for(int i=3;i<lp;i++){            j=f[i];            while(j>2 && (p[j].c!=p[i].c || p[j].v!=p[i].v) ) j=f[j];            /*             如果当前的p[i]与p[j]不匹配,那么j需要重新回到f[j]             再去判断当前的p[i]与p[j]是否相等             如果相等 f[i+1]=j+1  否则直接重头开始重新匹配             自己模拟下过程的话很好理解的  感觉节省的就是在匹配了一定的长度下发现不同了             但是又不能浪费了j从开始跑上来的值  这里利用了这个f[j]            */            if(p[j].c==p[i].c && p[j].v==p[i].v) f[i+1]=j+1;            else f[i+1]=2;        }        j=2;        for(int i=2;i<ls;i++){            while(j>2 && (s[i].c!=p[j].c || s[i].v!=p[j].v)) j=f[j];            if(s[i].c==p[j].c && s[i].v==p[j].v) j++;            /*                如果当前的s[i]与p[j]不匹配,那么j需要重新回到f[j](也就是前一个字符匹配的,避免浪费)                    再拿更新的j值去寻找当前的s[i]与p[j]是否匹配  这里就是利用之前已经匹配的长度,节省了时间                如果s[i]==p[j] 那么肯定j++啊                满足条件的话直接更新anw            */            if(j==lp){                int k=i-lp+2;                if(s[k].c==p[1].c && s[i+1].c==p[lp].c && s[k].v>=p[1].v && s[i+1].v>=p[lp].v) ans++;                j=f[j];            }        }    }    cout<<ans<<endl;}/*5 43-a 2-b 4-c 3-a 2-c2-a 2-b 4-c 4-a10 31-b 1-a 2-b 1-a 1-b 1-a 4-b 1-a 1-a 2-b1-b 1-a 1-b4 38-b 2-a 7-b 3-a3-b 2-b 1-a4 27-a 3-b 2-c 11-a3-a 4-a10 61-a 1-b 1-a 1-b 1-a 1-b 1-a 1-b 1-a 1-b1-a 1-b 1-a 1-b 1-a 1-b0 0 1 2 0 0*/


0 0
原创粉丝点击