zoukankan      html  css  js  c++  java
  • COGS 902 乐曲主题 题解 & hash入门贺

    【题意】

    给定一个长为n的序列,元素都是不超过88的正整数,求序列中主题的最大长度。

    所谓主题是指在序列中出现了至少两次并且不相交的子串。特别的,主题可以变调,也就是说如果一个子串全部加上或减去一个数后与另一个子串相同,那么也认为它们是相同的。

    对于100%的数据,n<=5000。

    【解法】

    所谓的变调不过是升降趋势相同,直接来一发差分就好。

    答案显然有单调性,长度越长主题越不容易出现,因此可以二分答案,每次只要查询长为ans的子串中是否存在相同且不相交的两个子串即可。

    查询子串是否相同可以用哈希实现,这样只要O(n)预处理一发h数组并递推幂取模,取hash值就果断O(1)了。

    关于hash的取模,可以直接用unsigned long long自动溢出取模(虽然这是最容易被卡的hash……)。

    贴个代码(也不知道出了什么事儿,莫名的折叠不了了,垃圾cnblogs):

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<map>
     5 #define ULL unsigned long long
     6 using namespace std;
     7 const int maxn=5010;
     8 const ULL T=173ull;
     9 void init();
    10 ULL hash(int,int);
    11 ULL h[maxn],pw[maxn],tmp;
    12 int n,a[maxn],L,R,M;
    13 bool ok;
    14 map<ULL,int>id;
    15 int main(){
    16 #define MINE
    17 #ifdef MINE
    18     freopen("theme.in","r",stdin);
    19     freopen("theme.out","w",stdout);
    20 #endif
    21     scanf("%d",&n);
    22     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    23     for(int i=n;i;i--)a[i]-=a[i-1];
    24     init();
    25     L=4;R=n;
    26     while(L<=R){
    27         M=(L+R)>>1;
    28         ok=false;
    29         for(int i=1;i+M-1<=n;i++){
    30             tmp=hash(i,M);
    31             if(id.count(tmp)){
    32                 if(id[tmp]<i-M){
    33                     ok=true;
    34                     break;
    35                 }
    36             }
    37             else id[tmp]=i;
    38         }
    39         if(ok)L=M+1;
    40         else R=M-1;
    41     }
    42     if(L<5)L=0;
    43     printf("%d",L);
    44 #ifndef MINE
    45     printf("
    -------------------------DONE-------------------------
    ");
    46     for(;;);
    47 #endif
    48     return 0;
    49 }
    50 inline void init(){
    51     for(int i=n;i;i--)h[i]=h[i+1]*T+(a[i]+1);
    52     pw[0]=1ull;
    53     for(int i=1;i<=n;i++)pw[i]=pw[i-1]*T;
    54 }
    55 inline ULL hash(int x,int l){return h[x]-h[x+l]*pw[l];}
    56 /*
    57 30
    58 25 27 30 34 39 45 52 60 69 79 69 60 52 45 39 34 30 26 22 18
    59 82 78 74 70 66 67 64 60 65 80
    60 Answer:
    61 9
    62 */

    【hash相关】

    虽说是抄的蓝书的hash……但不管怎么说自己算是会写hash了……好感动……

    如果字符串给定,询问的串都是它的子串,那么可以O(n)预处理,O(1)查询。

    具体来说,定义后缀hash函数为

    hi=Tn-i+1si+Tn-isi+1+……+sn,其中T代表字符集大小。

    那么利用秦九韶大法,有如下递推式:

    hi=hi+1*T+si

    然后就可以happy的O(n)推出所有h值啦。

    查询的时候,记以x开头,长为l的子串的hash值为hash(x,l),那么有

    hash(x,l)=Tlsx+Tl-1sx+1+……+sx+l-1

    由上面h函数的公式,可以推出

    hash(x,l)=hx-Tlhx+l

    然后就可以happy的O(1)查询啦。

    233333333
  • 相关阅读:
    Selenium简单测试页面加载速度的性能(Page loading performance)
    Selenium Page object Pattern usage
    Selenium如何支持测试Windows application
    UI Automation的两个成熟的框架(QTP 和Selenium)
    分享自己针对Automation做的两个成熟的框架(QTP 和Selenium)
    敏捷开发中的测试金字塔(转)
    Selenium 的基础框架类
    selenium2 run in Jenkins GUI testing not visible or browser not open but run in background浏览器后台运行不可见
    eclipse与SVN 结合(删除SVN中已经上传的问题)
    配置Jenkins的slave节点的详细步骤适合windows等其他平台
  • 原文地址:https://www.cnblogs.com/hzoier/p/5962171.html
Copyright © 2011-2022 走看看