清北学堂学习总结 day2 字符串 练习

1.hash表(哈希表)

codevs 2147 数星星--简单哈希

时间限制: 3 s

空间限制: 64000 KB

题目等级 : 钻石 Diamond

题目描述 Description

小明是一名天文爱好者,他喜欢晚上看星星。这天,他从淘宝上买下来了一个高级望远镜。他十分开心,于是他晚上去操场上看星星。

不同的星星发出不同的光,他的望远镜可以计算出观测到的星星发出的光的数值W。小明当然想尽可能地多看到星星,于是他每看到一颗星星,就要看看他之前有没有看过这颗星星。但是他看的星星太多了,他根本数不过来,于是他让你帮忙。

输入描述 Input Description

共有两行,第一行只有一个整数,为小明观测到的星星的数量n。第二行有n个整数,每两个整数由一个空格隔开,分别为小明观测到每颗星星的光的数值W[1]-W[n]。

输出描述 Output Description

只有一行,这一行共有n个数字0或1。0表示对应的星星之前没有观测到,1表示对应的星星之前已经看过了。注意:数字之间没有空格!

样例输入 Sample Input

5

1 5 5 4 1

样例输出 Sample Output

00101

数据范围及提示 Data Size & Hint

样例是往往是骗人的,本题中

30%的数据,0<n≤5000。

20%的数据,-20000≤W≤20000。

60%的数据,0<n≤50000。

100%的数据,0<n≤500000;-2000000000≤W≤2000000000。

分类标签 Tags 点此展开

哈希表 线性结构

#include<iostream>
using namespace std;
#define mod 500009/*取>500000的最小质数即可*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
long long hash_table[mod*2];
int n,w[mod];
int main()
{
    memset(hash_table,-128,sizeof(hash_table));
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&w[i]);
        int k=abs(w[i])%mod;
        bool flag=false;
        while(hash_table[k]>=-2000000000)/*you shu le*/
        {
            if(hash_table[k]==w[i])
            flag=true;
            k++;

        }
        hash_table[k]=w[i];
        if(flag)
        printf("1");
        else printf("0");

    }
    return 0;
}

2.KMP算法[POJ3461]乌力波

法国作家乔治·佩雷克(Georges Perec,1936-1982)曾经写过一本书,《敏感字母》(La disparition),全篇没有一个字母‘e’。他是乌力波小组(Oulipo Group)的一员。下面是他书中的一段话:

Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…

佩雷克很可能在下面的比赛中得到高分(当然,也有可能是低分)。在这个比赛中,人们被要求针对一个主题写出甚至是意味深长的文章,并且让一个给定的“单词”出现次数尽量少。我们的任务是给评委会编写一个程序来数单词出现了几次,用以得出参赛者最终的排名。参赛者经常会写一长串废话,例如500000个连续的‘T’。并且他们不用空格。

因此我们想要尽快找到一个单词出现的频数,即一个给定的字符串在文章中出现了几次。更加正式地,给出字母表{‘A‘,‘B‘,‘C‘,...,‘Z‘}和两个仅有字母表中字母组成的有限字符串:单词W和文章T,找到W在T中出现的次数。这里“出现”意味着W中所有的连续字符都必须对应T中的连续字符。T中出现的两个W可能会部分重叠。

【输入格式】

输入包含多组数据。

输入文件的第一行有一个整数,代表数据组数。接下来是这些数据,以如下格式给出:

第一行是单词W,一个由{‘A‘,‘B‘,‘C‘,...,‘Z‘}中字母组成的字符串,保证1<=|W|<=10000(|W|代表字符串W的长度)

第二行是文章T,一个由{‘A‘,‘B‘,‘C‘,...,‘Z‘}中字母组成的字符串,保证|W|<=|T|<=1000000。

【输出格式】

对每组数据输出一行一个整数,即W在T中出现的次数。

【样例输入】

3

BAPC

BAPC

AZA

AZAZAZA

VERDI

AVERDXIVYERDIAN

样例输出

1

3

0

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#define MT 1000100
#define MW 10100
char w[MW],t[MT];
int ans=0;
int fail[MW];
void input()
{
    memset(w,0,sizeof(w));
    memset(t,0,sizeof(t));
    memset(fail,0,sizeof(fail));
    scanf("%s%s",w,t);
}
void make_fail()
{
    int k=0;
    int lenw=strlen(w);
    fail[0]=0;//
    for(int i=1;i<=lenw;++i)//
    {
        while(k>0&&w[i]!=w[k])
        k=fail[k-1];//
        if(w[i]==w[k])
        k++;
        fail[i]=k;
    }
}
void kmp()
{
    int lent=strlen(t);//mu
    int lenw=strlen(w);
    int k=0;
    for(int i=0;i<=lent;++i)
    {
        while(k>0&&t[i]!=w[k])
        k=fail[k-1];//
        if(t[i]==w[k])
        {
            k++;
        }
        if(k==lenw)
        {
            ans++;
            k=fail[k-1];
        }
    }
}
int main()
{
    int t1;
    scanf("%d",&t1);
    while(t1--)
    {
        input();
        make_fail();
        ans=0;
        kmp();
        printf("%d\n",ans);
    }
    return 0;
}

3.【AC自动机】

BZOJ 3172: [Tjoi2013]单词

Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
3
1

代码:

#include<iostream>
using namespace std;
#define N 1000100/*最长字符串的长度*/
#include<cstring>
#include<cstdio>
int topt=0,n;
struct Trie{
    int nxt[26],cnt,fail;
    Trie()
    {
        memset(nxt,0,sizeof(nxt));
        cnt=fail=0;/*结构体初始化*/
    }
}trie[N];
int pos[201],que[N],head=-1,tail=-1;
void build_trie(int k,char*str)/*建trie书的过程*/
{
    int now=0;
    while(*str)
    {
        if(!trie[now].nxt[*str-‘a‘])
        trie[now].nxt[*str-‘a‘]=++topt;
        now=trie[now].nxt[*str-‘a‘];
        str++;
        trie[now].cnt++;/*记录该前缀出现的次数*/
    }
    pos[k]=now;/*记录第k个单词终点的节点编号*/
}
void input()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        char s[N];
        scanf("%s",s);
        build_trie(i,s);
    }
}
void make_fail()/*生成fail数组*/
{
    int now=0;
    trie[now].fail=0;
    for(int i=0;i<26;++i)/*根节点及第一层点的入队处理*/
    {
        if(!trie[now].nxt[i]) continue;
        que[++tail]=trie[now].nxt[i];
        trie[trie[now].nxt[i]].fail=0;
    }
    int p;
    while(head<tail)
    {
        ++head;
        now=que[head];
        for(int i=0;i<26;++i)
        {
            if(!trie[now].nxt[i]) continue;
            que[++tail]=trie[now].nxt[i];/*如果存在,就入队*/
            p=trie[now].fail;/*p是该节点父亲的fail指针*/
            while(!trie[p].nxt[i]&&p)/*回调的过程*/
            p=trie[p].fail;
            if(trie[p].nxt[i])
              trie[trie[now].nxt[i]].fail=trie[p].nxt[i];
            else trie[trie[now].nxt[i]].fail=0;
        }
    }
    for(int i=tail;i>=0;--i)
    trie[trie[que[i]].fail].cnt+=trie[que[i]].cnt/*关键:从队列的反方向,因为是广搜,所以反方向的1<--3<--5都有该单词的cnt,只有反向才能把cnt一层层传上来,因为fail不一定会指向我们想要的位置*/;
    for(int i=1;i<=n;++i)
    printf("%d\n",trie[pos[i]].cnt);/*这是该单词的这终结点,但是也许别的单词中也会包括该单词,因为这是广搜,所以包含该单词的单词终结位置的fail一定指向当前这个单词,上面那一步就是,把这里的单词数转移上去*/
}
int main()
{
    input();
    make_fail();
    return 0;
}

4.【manacher算法--回文串】

POJ 3974 Palindrome

Time Limit: 15000MS   Memory Limit: 65536K
Total Submissions: 6831   Accepted: 2534

Description

Andy the smart computer science student was attending an algorithms class when the professor asked the students a simple question, "Can you propose an efficient algorithm to find the length of the largest palindrome in a string?"

A string is said to be a palindrome if it reads the same both forwards and backwards, for example "madam" is a palindrome while "acm" is not.

The students recognized that this is a classical problem but couldn‘t come up with a solution better than iterating over all substrings and checking whether they are palindrome or not, obviously this algorithm is not efficient at all, after a while Andy raised his hand and said "Okay, I‘ve a better algorithm" and before he starts to explain his idea he stopped for a moment and then said "Well, I‘ve an even better algorithm!".

If you think you know Andy‘s final solution then prove it! Given a string of at most 1000000 characters find and print the length of the largest palindrome inside this string.

Input

Your program will be tested on at most 30 test cases, each test case is given as a string of at most 1000000 lowercase characters on a line by itself. The input is terminated by a line that starts with the string "END" (quotes for clarity).

Output

For each test case in the input print the test case number and the length of the largest palindrome.

Sample Input

abcbabcbabcba
abacacbaaaab
END

Sample Output

Case 1: 13
Case 2: 6

题目大意:求最长回文子串的长度

#define L 1000100
#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
using namespace std;
char s[L*2+100];
int p[L*2+100],id;
int lens;
int ans=-1;
void input()
{
    lens=strlen(s);
    for(int i=lens;i>=0;--i)
    {
        s[i+i+2]=s[i];/*预处理加#,偶数是原字母,奇数和0是#*/
        s[i+i+1]=‘#‘;
    }
    s[0]=‘#‘;
}
void manacher()
{
    ans=0;
    id=0;p[id]=0;
    for(int i=1;i<=lens*2+2;++i)/*别忘了跑2*lens+2才可以*/
    {
        if(id+p[id]>i)
        p[i]=min(p[2*id-i],id+p[id]-i);
        while(s[i+p[i]]==s[i-p[i]])
        p[i]++;
        if(i+p[i]>id+p[id])
        id=i;
        ans=max(ans,p[i]);
    }
}
int main()
{
    int topt=0;
    while(scanf("%s",s)==1)
    {
        ++topt;
        if(strcmp(s,"END")==0) break;
        input();
        manacher();
        printf("Case %d: %d\n",topt,ans-1);/*ans-1是因为添加了#*/
        memset(s,0,sizeof(s));/*不要忘记初始化*/
        memset(p,0,sizeof(p));
   }
    return 0;
}

时间: 2024-10-01 04:26:27

清北学堂学习总结 day2 字符串 练习的相关文章

清北学堂学习总结 day1 数据结构 练习

1.二叉搜索树 STL set直接做就可以了 2.树状数组+差分数列: codevs 1081 线段树练习 2 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作 1:给区间[a,b]的所有数都增加X 2:询问第i个数是什么? 输入描述 Input Description 第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数.如果第一个数是1,后接3个正

清北学堂2017NOIP冬令营入学测试 P4744 A’s problem(a)

清北学堂2017NOIP冬令营入学测试 P4744 A's problem(a) 时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试题,每三天结算一次成绩.参与享优惠 描述 这是一道有背景的题目,小A也是一个有故事的人.但可惜的是这里纸张太小,小A无法把故事详细地说给大家听.可能小A自己也讲不清楚自己的故事,因为如果讲清了,也就没有这道题目了-- 小A的问题是这个样子,它找到了n份不同的工作,第i份工作每个月有ai的工资,每份工作需要小A每天

铁轨 清北学堂 线段树

铁轨 清北学堂 线段树 [题目描述] R 国的铁轨经常会进行重新修建. R 国是一个细长的国家,一共有 n 个城市排成一排,首都位于 1 号城市,相邻两个城市之间有铁路相连. 每次新建铁轨的时候,一定是从首都开始修建,直到某一个城市为止,这其间的铁路都会变成新版本的设 施,而旧设施会被拆除.然而,由于 R 国的工程师脑子不太好使,任意两种不同版本的铁路之间都无法连 接,因此必须要进行换乘. 现在给出你修建铁轨的操作,小 R 时不时第会想问你,如果在第 x 个城市到第 y 个城市之间随机选择一个

关于树的一点学习【清北学堂】

我主要在这里讲的是树的直径求法和树的重心求法 树的直径,指的就是树上距离最远两点间的一条路径. 求树的直径的方法是,首先我任选一个点,找到与它距离最远的点,记为s 再以s为起点找离他最远的点,记为v s到v的路径即为树的直径 树的重心指的就是树上一个节点,把这个节点挖掉之后,剩下很多联通块  而重心就让这些联通块中最大的那个最小 树的重心有两种求法 一种是枚举每一个点 看把他挖掉之后会发生什么 第二种是DFS求出每个节点联通块大小 可能有人说每个节点不都连着整个树么 所以说这个联通块是算上节点自

清北学堂 最大速度

最大速度 (maxv.pas/c/cpp) [问题描述] Ron的老爸的Flying Car出了些问题,现在必须要在地上跑到很大的速度才能飞起来,但是Flying Car飞起来的那一刻不能被麻瓜看到.为了确保安全飞起来,需要知道车到可以飞起来的地方时所能达到的最大速度.他的Flying Car一开始拥有一个初速度,移动一次增加速度1:因为车道很窄,宽度只有1,所以仅当要转向的方向有路时才能转,左转一次减少速度35,右转一次减少速度40,当前进.左转.右转都无路可走的时候,调头(连左转两次或连右转

2017清北学堂集训笔记——动态规划Part2

啊~到下午啦,我们进入Part2!--一个简洁的开头 我们来探讨第一类问题--路径行走问题 经典例题:方格取数(Luogu 1004) 设有 N*N 的方格图 (N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 0.* 某人从图的左上角的 A 点出发,可以向下行走,也可以向右走,直到到达右下角的 B 点.在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 0).* 此人从 A 点到 B 点共走两次,试找出 2 条这样的路径,使得取得的数之和为最大.- 与数字金字塔

清北学堂2017NOIP冬令营入学测试

P4744 A's problem(a) 时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试题,每三天结算一次成绩.参与享优惠 描述 这是一道有背景的题目,小A也是一个有故事的人.但可惜的是这里纸张太小,小A无法把故事详细地说给大家听.可能小A自己也讲不清楚自己的故事,因为如果讲清了,也就没有这道题目了-- 小A的问题是这个样子,它找到了n份不同的工作,第i份工作每个月有ai的工资,每份工作需要小A每天工作8小时,一周工作7天.小A想知道性价

清北学堂 NOIP2017模拟赛 越赛越心塞

连续考了一个星期发现自己真的是手感型选手,成绩全靠天意.手感好了码出200+也没什么问题,推出式子并且打出自己都不信的操作也有过.手感差了......就一个呵呵二字. 然后开始是T总让我们休息了一个星期五不考试?本来还以为自己活在梦里然后发现星期天上午没假放了心里真是MMP. 星期五好好输出了一波联赛题,早早就睡了不提. 星期六上午,母后:“今天早上直接去机房不去教室了.” 结果到八点半才开考喵喵喵? UPD:2017年9月23日 20:19:23 Day1 看完题目一脸绝望. T1是我初二普及

济南清北学堂游记 Day 7.

完结撒花? 最后的模拟赛与讲题.大家似乎仍然乐在其中,虽然看评测结果,仍然是满地红. 其实到了最后已经是没有多少可写的了..... 一个精彩的地方是晚上填表的时候,群里炸锅了已经.到处都在刷CCL老师的表情23333 (CCL表示让他们疯去吧) 大概的想了想这几天的内容,在最后的七天里,要做的事情还有很多. (学校模拟赛的出题任务又甩给我了...星期天就要比的..) 先列一些出来吧. 11.4 搞三个题,如果有时间就复习一下排序 查找 二分等基础操作. 11.5 树与图的相关算法(包括新增的二分