• 【经典dp】hdu4622Reincarnation


    呕  卡64M内存卡了好久

    题目描述

    题目大意

    给出一个字符串 S,每次询问一个区间的本质不同的子串个数。$|S| le 2000$.


    题目分析

    首先无脑$n^2$个set开起来:MLE

    稍微想想这个东西是能够区间dp的:对于一个字符串$[l,r]$,它的存在首先给所有包含$[l,r]$的$f[i][j]$贡献$1$;考虑相同的字符串下一次出现的位置$[l',r']$,那么对所有包含$[l,r']$的$f[i][j]$贡献$-1$。最后再按照顺序累加一下即可。

    第一次:std::map存一个哈希值上一次出现的位置,MLE

    第二次:手写哈希表,$mod 8000007$挂链,MLE

    第三次:手写哈希表,$mod 5000007$挂链,MLE

    第四次:手写哈希表,$mod 10007$挂链,TLE?

    第五次:手写哈希表,$mod 500007$挂链、查询时候顺带后续修改,MLE???

    嗯?这啥玩意?

    啧。后来意识到枚举不同长度的时候,哈希表里历史记录值都是没用的。所以每次枚举长度都应该重置哈希表。而且这样一来,哈希表模数和空间就可以开小了。

    还听说这个经典问题有一个$O(n)$做法?

    网上找了一下只有两个类似的是:

    1.loj#6070. 「2017 山东一轮集训 Day4」基因  强制在线询问$s[lcdots r]$中有多少本质不同的回文子串 $nle 10^5,qle 2 imes10^5$

    2.「湖南省队集训2018 Day2」有趣的字符串题  每个询问会询问一段区间的本质不同回文子串个数 $nle 3 imes 10^5,mle 10^6$

    不过这两个题都要用到回文子串的性质:“一个串的所有回文后缀可以被划分成不超过log个等差数列”。所以网上尚没有找到这个问题的$O(n)$解法?

     1 #include<bits/stdc++.h>
     2 typedef unsigned long long uint;
     3 const int maxn = 2035;
     4 const int maxp = 2035;
     5 uint base = 2333;
     6 
     7 struct node
     8 {
     9     uint num;
    10     int val;
    11     node(uint a=0, int b=0):num(a),val(b) {}
    12 }edges[maxp];
    13 struct Hash_Table
    14 {
    15     #define MO 10007
    16     int head[10035],nxt[maxp],edgeTot;
    17     void init(){edgeTot=0,memset(head, -1, sizeof head);}
    18     int query(uint x, int c)
    19     {
    20         for (int i=head[x%MO]; i!=-1; i=nxt[i])
    21             if (edges[i].num==x){
    22                 std::swap(c, edges[i].val);
    23                 return c;
    24             }
    25         edges[++edgeTot] = node(x, c), nxt[edgeTot] = head[x%MO], head[x%MO] = edgeTot;
    26         return 0;
    27     }
    28     #undef MO
    29 }g;
    30 int T,n,q,l,r;
    31 char s[maxn];
    32 int f[maxn][maxn];
    33 uint pwr[maxn],hsh[maxn],val;
    34 
    35 uint hash(int l, int r)
    36 {
    37     return hsh[r]-hsh[l-1]*pwr[r-l+1];
    38 }
    39 int main()
    40 {
    41 //    freopen("hdu4622.in","r",stdin);
    42 //    freopen("hdu4622.out","w",stdout);
    43     pwr[0] = 1;
    44     for (int i=1; i<=2000; i++)
    45         pwr[i] = pwr[i-1]*base;
    46     for (scanf("%d",&T); T; --T)
    47     {
    48         scanf("%s",s+1);
    49         n = strlen(s+1);
    50         for (int i=1; i<=n; i++) hsh[i] = hsh[i-1]*base+s[i]-'a'+1;
    51         for (int i=1; i<=n; i++)
    52             for (int j=i; j<=n; j++) f[i][j] = 0;
    53         for (int d=1; d<=n; d++)
    54         {
    55             g.init();
    56             for (int i=1,pos; i+d-1<=n; i++)
    57             {
    58                 val = hash(i, i+d-1), pos = g.query(val, i);
    59                 if (pos) --f[pos][i+d-1];
    60                 ++f[i][i+d-1];
    61             }
    62         }
    63         for (int i=n; i>=1; i--)
    64             for (int j=i; j<=n; j++)
    65                 f[i][j] += f[i+1][j]+f[i][j-1]-f[i+1][j-1];
    66         for (scanf("%d",&q); q; --q)
    67             scanf("%d%d",&l,&r), printf("%d
    ",f[l][r]);
    68     }
    69     return 0;
    70 }

    END

  • 相关阅读:
    Android应用程序请求SurfaceFlinger服务创建Surface的过程分析
    和菜鸟一起学linux总线驱动之初识i2c驱动主要结构
    和菜鸟一起学linux之container_of实例
    和菜鸟一起学linux总线驱动之初识spi驱动主要结构
    和菜鸟一起学android4.0.3源码之按键驱动短长按功能
    和菜鸟一起学linux总线驱动之初识i2c总线协议
    程序溢出的基础和原理
    Network Information Detection程序作品+源代码
    Network Information Detection程序作品+源代码
    渗透asp后门源代码
  • 原文地址:https://www.cnblogs.com/antiquality/p/11202803.html
Copyright © 2020-2023  润新知