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——常用结构

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

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

  • 相关阅读:
    Azure 虚拟机安全加固整理
    AzureARM 使用 powershell 扩容系统磁盘大小
    Azure Linux 云主机使用Root超级用户登录
    Open edX 配置 O365 SMTP
    powershell 根据错误GUID查寻错误详情
    azure 创建redhat镜像帮助
    Azure Powershell blob中指定的vhd创建虚拟机
    Azure Powershell 获取可用镜像 PublisherName,Offer,Skus,Version
    Power BI 连接到 Azure 账单,自动生成报表,可刷新
    Azure powershell 获取 vmSize 可用列表的命令
  • 原文地址:https://www.cnblogs.com/mikuo/p/12099085.html
Copyright © 2011-2022 走看看