zoukankan      html  css  js  c++  java
  • STL中map的简单使用&常数优化

    本地某大学校赛某题[flower]的总结——常数优化&Map的浅略使用

    关于这道题,是我赛场上比较遗憾的(~~我连题都没读懂~~)
    把题面抄下来先

    ### The flower
    Every problem maker has a flower in their heart out of love for ACM. As a famous problem maker, hery also has a flower.
    Hery define string T as flower−string if T appears more than twice in string S and |T|=k. Hery wants you to find how many flower−string in S.

    输入格式
    The first line contains a string S consist of ′f′,′l′,′o′,′w′,′e′,′r′ and an integer k.
    (1≤|S|≤1e5,1≤k≤100)

    输出格式


    Output an integer m in the first line, the number of flower−string in S.
    Next m lines, each line contains a flower−string and the lexicographical order of them should be from small to large


    样例
    **input**


    flowerflowerflower 3


    **output**


    4
    flo
    low
    owe
    wer



    大致的翻译就是每只出题人都在心里种着一颗花(???)
    定义一个flower-string ,由“f,l,o,w,e,r”组成,规定其长度为k,
    在S中,问存在多少个长度为k的flower-string。
    然后只有出现过两次以上的flower-string 才能算做flower-string,输出时要按字典序。

    因为这个样例太特殊了,正好都是flower,所以我就以为是在flower中找到长度为k的string,而且以为只要结尾是wer就好,因此我就想,他最多也就6个,因为即使是从f开始,长度为7的串,进行六次操作,也会回到wer(相当于接龙接到最后,几个串里的字母去重后就是flower)。

    然而,刚刚我的翻译也能看的出来,这题根本不是这个意思。

    所以这个题什么意思呢?就是找在一个长串中,有多少个出现2次以上的(不包括二次)长度为k的字串。

    于是,就有一个O(N)的想法,就是从长串的每一个字母打头,做一个复杂为k的循环,这样最大复杂度就是k*N,也就是1e7,

    所以这里要用到map!

    ------------
    为什么要用到map?因为要统计一下,某一个字串出现的次数,那么假如说发现了一个长度为k的字串,如何统计它的出现次数,保证它出现了三次?(三次以上出现的话就要进行去重而不是记录的操作了)。
    我所知道的是,对于一个数,判断其是否出现过,可以用bool数组(素数筛用到的)
    也可以用一个int数组,让它的值保证为3再记录

    而这里要进行标记的[键],(他们都是这么叫的),是一个string。因此无法用下标类型为int的容器来操作。

    ### MAP

    经过学习了解,我对map有一个理解。

    map<key_type,value_type>x;
    //定义了一个以key_type作键的,value_type作值的"容器"

    那么在这道题中,需要的是一个map<string,int>h;

    我的通俗(浅显)理解是,我这里的map定义了一个“桶”,这个桶上面的标号不是1,两,3,4,5......而是类似a22,bkk,cmm,d45一类的字符串;

    所以说,我所理解的map定义容器的逻辑是:map<“桶”所用名字的类型,“桶”里装的东西>;
    那么也就近似的认为,数组就是map<int,int>h;然而map不需要你进行范围的设置,也就是说你不用管它里面要存多少(当然存的多肯定会爆)

    举个例子,int a[1000],规定了下标只能是0~999,数组里面存的数可以是int类型,而map<int,int>里面则没有规定下标,你在记录一个值的时候,直接将这个值的下标(可以是任意的你想要的在int范围内的下标)给作为键,再将这个值存进去。

    所以这道题可以用map<string,int>h;从S中枚举所有长度为k的string,然后这些串都作为键,用value来记录出现的次数。

    因此这个程序的核心就出来了。


    ------------

    #include<bits/stdc++.h>
    using namespace std;
    string k[101000];
    map<string,int>m;
    int main()
    {
    string a;
    cin>>a;
    int n;
    cin>>n;
    int sum=0;
    for(int i=0;i<a.size()-n+1;i++)//从每一个字符做n次枚举
    {    
    string b;//中转string
    for(int j=i;j<=i+n-1;j++)//枚举
    {
    b+=a[j];//把k个char一个个塞到这个string里
    }
    m[b]++;//让名为b的桶里的值加一,代表其出现一次
    if(m[b]==3) //等到这个桶里的值达到三,则符合要求,增加最终结果数量的值,并将此string存到结果串里。
    {
    sum++;
    k[sum]=b;
    }
    }
    cout<<sum<<endl;
    sort(k+1,k+sum+1);
    for(int i=1;i<=sum;i++)
    {
    cout<<k[i];
    printf("
    ");//对于string的输出唯一能做的时间优化,大概就是格式化换行了。
    }
    return 0;
    }


    ------------

    当我觉得我终于要用map解题的时候,我发现我tle了(我太弱了)
    于是我再想怎么优化,然后我首先想到了氧气。

    #pragma GCC optimize(2)//开个氧气优化



    结果我把氧气放进去的时候,依然超时。

    我就很奇怪,然而这个时候要就寝了,于是就只好暂停...

    于是时间来到了第二天。

    我一大早吃完饭就迅速跑向机房(~~这个好像很废话~~)

    然后当我这个蒟蒻百思不得其解的时候,来了一位机房大佬,一眼就看出了我超时的原因,在于

    for(int i=0;i<a.size()-n+1;i++)



    他提醒我这个计算串长度的操作在每一次循环都会做一次!
    (蒟蒻恍然大悟)
    于是我才想到了常常被我忽略的常数优化。

    而据说stl中.size()操作是o(n)的。
    于是n*n就很明显会爆了。

    那么就要讲我在这道题学到的另一个教训了。
    ### 常数优化

    其实就是对于一个要多次调用的常数预处理一下,然后就可以减少时间。

    比如这道题

    for(int i=0;i<a.size()-n+1;i++)


    然后我再改一下循环里的这一点,成为p,就可以见效了。

    ### 小结

    常数优化——常用技巧

    map——常用结构

    嗯,参加这个比赛还是有挺大收益的(仅这道题就挺多)。

    当然对于这两点的应用和理解,今后肯定会更频繁和深入,我还有很多学的东西啊。

  • 相关阅读:
    CSS的display小记
    Oracle PL/SQL中的循环处理(sql for循环)
    Windows下Git服务器搭建及使用过程中的一些问题
    IIS故障问题(Connections_Refused)分析及处理
    [转载]Function.apply and Function.call in JavaScript
    CentOS中文乱码问题的解决方法
    sed之G、H、g、h使用
    Linux命令:chgrp chown chmod
    javascirpt倒计时
    linux:sed高级命令之n、N
  • 原文地址:https://www.cnblogs.com/mikuo/p/12099085.html
Copyright © 2011-2022 走看看