zoukankan      html  css  js  c++  java
  • P3498 [POI2010]KOR-Beads

    传送门

    哈希表

    枚举子串长度 k

    把每个子串的哈希值加到哈希表里

    用哈希表判重

    因为子串可以反转

    所以要两个哈希

    一个从前往后,一个从后往前

    复杂度为O(n + n/2 + n/3+ ... + n/n) 约等于 O(n ln n)

    但是每次长度k更新都要清空哈希表

    非常耗时(只有60分)

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef unsigned long long ull;
    const int mo=1e6+7;//模数
    const long long base=1e9+7;//这里base要大一些,不然容易冲突
    int n,a[mo+10],mx,ans[mo+10],tot;
    ull h1[mo+10],h2[mo+10],fac[mo+10],hset[mo+10];//前缀哈希,后缀哈希以及哈希表
    int from[mo+10],fir[mo+10],cnt;//哈希表的实现用链式前向星
    inline void add(ull hs)//添加一个值到哈希表里
    {
        int t=hs%mo;
        from[++cnt]=fir[t];
        fir[t]=cnt;
        hset[cnt]=hs;
    }
    inline bool find(ull hs)//判断重复
    {
        int t=hs%mo;
        for(int i=fir[t];i;i=from[i])
            if(hset[i]==hs) return 1;
        return 0;
    }
    int main()
    {
        cin>>n;
        fac[0]=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            fac[i]=fac[i-1]*base;
            h1[i]=h1[i-1]*base+a[i];
        }
        for(int i=n;i;i--)
            h2[i]=h2[i+1]*base+a[i];
        //预处理前缀后缀哈希值
        for(int i=1;i<=n;i++)
        {
            cnt=0;
            memset(from,0,sizeof(from));
            memset(fir,0,sizeof(fir));
            memset(hset,0,sizeof(hset));
            //每次清空哈希表
            int s=0;
            for(int j=i;j<=n;j+=i)
            {
                ull hs1=h1[j]-h1[j-i]*fac[i];//取出子串哈希值
                if(find(hs1)) continue;//判重
                ull hs2=h2[j-i+1]-h2[j+1]*fac[i];//取出子串反转后的哈希值
                if(find(hs2)) continue;//判重
                add(hs1); add(hs2);//把两个哈希值都加到哈希表里
                s++;
            }
            if(s>mx) mx=s,ans[tot=1]=i;
            else if(s==mx) ans[++tot]=i;
            //尝试更新答案
        }
        cout<<mx<<" "<<tot<<endl;
        for(int i=1;i<=tot;i++)
            printf("%d ",ans[i]);
        return 0;
    }
    60分代码

    所以考虑增加一个时间戳tim

    记录当前哈希值是什么时候加入的

    就不用清空了

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef unsigned long long ull;
    const int mo=1e7+7;//模数
    const long long base=1e9+7;//这里base要大一些,不然容易冲突
    int n,a[mo+10],mx,ans[mo+10],tot;
    ull h1[mo+10],h2[mo+10],fac[mo+10],hset[mo+10];//前缀哈希,后缀哈希以及哈希表
    int from[mo+10],fir[mo+10],cnt,tim[mo+10];//哈希表的实现用链式前向星
    inline void add(ull hs,int k)//添加一个值到哈希表里,k为时间
    {
        int t=hs%mo;
        from[++cnt]=fir[t];
        fir[t]=cnt;
        hset[cnt]=hs;
        tim[cnt]=k;//时间戳,记录当前哈希值是在什么时候加入的
    }
    inline bool find(ull hs,int k)//判断重复
    {
        int t=hs%mo;
        for(int i=fir[t];i;i=from[i])
            if(hset[i]==hs&&tim[i]==k) return 1;
        return 0;
    }
    int main()
    {
        cin>>n;
        fac[0]=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            fac[i]=fac[i-1]*base;
            h1[i]=h1[i-1]*base+a[i];
        }
        for(int i=n;i;i--)
            h2[i]=h2[i+1]*base+a[i];
        //预处理前缀后缀哈希值
        for(int i=1;i<=n;i++)
        {
            int s=0;
            for(int j=i;j<=n;j+=i)
            {
                ull hs1=h1[j]-h1[j-i]*fac[i];//取出子串哈希值
                if(find(hs1,i)) continue;//判重
                ull hs2=h2[j-i+1]-h2[j+1]*fac[i];//取出子串反转后的哈希值
                if(find(hs2,i)) continue;//判重
                add(hs1,i); add(hs2,i);//把两个哈希值都加到哈希表里
                s++;
            }
            if(s>mx) mx=s,ans[tot=1]=i;
            else if(s==mx) ans[++tot]=i;
            //尝试更新答案
        }
        cout<<mx<<" "<<tot<<endl;
        for(int i=1;i<=tot;i++)
            printf("%d ",ans[i]);
        return 0;
    }
  • 相关阅读:
    IO 单个文件的多线程拷贝
    day30 进程 同步 异步 阻塞 非阻塞 并发 并行 创建进程 守护进程 僵尸进程与孤儿进程 互斥锁
    day31 进程间通讯,线程
    d29天 上传电影练习 UDP使用 ScketServer模块
    d28 scoket套接字 struct模块
    d27网络编程
    d24 反射,元类
    d23 多态,oop中常用的内置函数 类中常用内置函数
    d22 封装 property装饰器 接口 抽象类 鸭子类型
    d21天 继承
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9634231.html
Copyright © 2011-2022 走看看