• 【经典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

  • 相关阅读:
    POJ 2923 Relocation (状态压缩,01背包)
    HDU 2126 Buy the souvenirs (01背包,输出方案数)
    hdu 2639 Bone Collector II (01背包,求第k优解)
    UVA 562 Dividing coins (01背包)
    POJ 3437 Tree Grafting
    Light OJ 1095 Arrange the Numbers(容斥)
    BZOJ 1560 火星藏宝图(DP)
    POJ 3675 Telescope
    POJ 2986 A Triangle and a Circle
    BZOJ 1040 骑士
  • 原文地址:https://www.cnblogs.com/antiquality/p/11202803.html
Copyright © 2020-2023  润新知