• P3498 [POI2010]KOR-Beads(hash表)


    P3498 [POI2010]KOR-Beads

    题解

    hash+hash表+调和级数


    关于调和级数(from baidu百科):

    调和级数发散的速度非常缓慢。举例来说,调和序列前10项的和还不足100。这是因为调和数列的部分和呈对数增长。特别地, [3] 
    其中
     
     
    是欧拉-马歇罗尼常数,而
      
    约等于
      
    ,并且随着 k趋于正无穷而趋于 0。这个结果由欧拉给出。

    在做题之前,我们需要先算算复杂度

    我们至少要枚举子串的长度,并取出每个子串。

    计算枚举的总复杂度

    O(n+n/2+n/3+n/4+...+n/n)(分数向下取整)== O(n*(1+1/2+1/3+1/4+...+1/n))(分数向下取整)<= O(n*(1+1/2+1/3+1/4+...+1/n))

    其中这个 1+1/2+1/3+1/4+...+1/n 通过一种叫调和级数的神奇方法可以得出 

    1+1/2+1/3+1/4+...+1/n ≈ ln n < log n

    ∴枚举的总复杂度 <= O( n log n )

    所以如果比较和记录的复杂度可以达到 O(1),我们就可以轻松愉快地(大雾)过掉了。

    于是我们想到用hash瞎搞

    我们预处理出主串的hash值,由于子串可以翻转,所以正序逆序都要算

    然后取出子串的hash值(方法见代码),扔到hash表里判重

    至于怎么搞hash表,用邻接表实现就好了。

    但是我们每次枚举都要先清空hash表,时间占用太大了。

    于是我们可以引入一个tim数组,存下时间戳,表示枚举长度 i 时这个子串被扔进去

    当 tim 不同时,说明这是上次枚举的数据,已经失效,可以直接覆盖

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read(){
        char c=getchar(); int x=0;
        while(c<'0'||c>'9') c=getchar();
        while('0'<=c&&c<='9') x=x*10+c-48,c=getchar();
        return x;
    }
    typedef unsigned long long ull;
    #define N 200005
    const ull bs=1e9+7;
    const ull Ph=13357771;
    int n,ans,pos[N],tp;
    int cnt,hd[Ph],nx[N*2],ti[N*2];
    ull a[N],fac[N],h1[N],h2[N],v[N*2];
    void ins(ull x,int nw){
        nx[++cnt]=hd[x%Ph]; hd[x%Ph]=cnt;
        ti[cnt]=nw; v[cnt]=x;
    }
    int ask(ull x,int nw){
        for(int i=hd[x%Ph];ti[i]==nw;i=nx[i])
            if(v[i]==x) return 0;
        return 1;
    }
    int main(){
        n=read(); fac[0]=1;
        for(int i=1;i<=n;++i){
            a[i]=read();
            fac[i]=fac[i-1]*bs;
            h1[i]=h1[i-1]*bs+a[i];
        }
        for(int i=n;i>=1;--i) h2[i]=h2[i+1]*bs+a[i];
        for(int k=1;k<=n;++k){
            if(n/k<ans) break;
            int tt=0; cnt=0;
            for(int i=1;i+k-1<=n;i+=k){
                ull p1=h1[i+k-1]-h1[i-1]*fac[k];
                ull p2=h2[i]-h2[i+k]*fac[k];
                if(ask(p1,k)&&ask(p2,k))
                    ins(p1,k),ins(p2,k),++tt;
            }
            if(tt>ans) ans=tt,pos[tp=1]=k;
            else if(tt==ans) pos[++tp]=k;
        }sort(pos+1,pos+tp+1);
        printf("%d %d
    ",ans,tp);
        for(int i=1;i<=tp;++i) printf("%d ",pos[i]);
        return 0;
    }
  • 相关阅读:
    UNIX环境高级编程——信号(API)
    UNIX环境高级编程——信号之kill、raise、killpg、alarm、pause、abort、sleep、usleep、nanosleep和setitimer函数
    UNIX环境高级编程——信号基本概述和signal函数
    UNIX环境高级编程——进程关系
    UNIX环境高级编程——system函数
    [Training Video
    [Selenium]重写拖拽dragWidgetToElementContainner()
    [Selenium]Grid模式下运行时打印出当前Case在哪台node机器上运行
    [Java]通过java获取计算机名
    [Selenium]点击下拉框之后,从下拉列表选择元素进行点击很容易失败
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9601263.html
Copyright © 2020-2023  润新知