• HDU4622 hash做法


    题意:给一个2e4长的字符串 ,1e4次询问,每次询问一个区间内字符串的子串有多少种。
    思路:字符串hash用来判重,之后dp预处理出每个区间的权值。复杂度On^2
    值得总结的两点是:

    1. 为了使判重近似O1,可以如下不影响复杂度,通过%来解决,并且建链表。
      判重之后这个问题就变成了给你1-n区间内所有子区间的权值,现在定义f(l,r)为区间[l,r]的所有子区间权值累加和怎么样On^2预处理出来。
    2. dp的预处理
      因为计算任意一个点为左端点时一定要长度从小到大枚举,一个新的点可以由已知条件【l,r-1】构成,但是缺少了以r为右端点的情况。已知条件有【l+1,r】,再去重。因为是定左端点,所以一定要从子区间小的左端点枚举,所以n枚举到1。如果是定右端点,就可以枚举1到n了。
      最后就有了这个kuangbin的板子
    #include <bits/stdc++.h>
    using namespace std;
    #define ull unsigned long long
    #define forn(i,n) for(int i=0;i<n;i++)
    #define for1(i,n) for(int i=1;i<=n;i++)
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    const int maxn = 2005;
    const int seed = 13331;
    const int mod = 10007;
    ull power[maxn],S[maxn];
    int ans[maxn][maxn];
    
    struct Hh{
        int head[mod],nex[maxn],size,f[maxn];
        ull state[maxn];
        void init(){
            size = 0;
            memset(head,-1,sizeof(head));
        }
        int insert(ull v,int id){
            int h = v%mod;
            for(int i = head[h];i!=-1;i = nex[i]){
                if(v==state[i]){
                    int x = f[i];
                    f[i] = id;
                    return x;
                }
            }
            f[size] = id;
            state[size] = v;
            nex[size] = head[h];
            head[h] = size++;
            return 0;
        }
    }H;
    
    int main(){
        IO;int t;cin>>t;
        power[0] = 1;
        for1(i,maxn-1) power[i] = power[i-1]*seed;
        while(t--){
            string s;cin>>s;
            int n = s.size();
            for1(i,n) S[i] = S[i-1]*seed+s[i-1];
            for1(i,n) for(int j = i;j<=n;j++) ans[i][j] = 1;
            for1(i,n){
                H.init();
                for(int j = 1;j<=n-i+1;j++){
                    int l =  H.insert(S[j+i-1]-S[j-1]*power[i],j);
                    ans[l][j+i-1]--;
                }
            }
            for(int i = n;i>=1;i--){
                for(int j = i+1;j<=n;j++){
                    ans[i][j] += ans[i+1][j]+ans[i][j-1]-ans[i+1][j-1];
                }
            }
            int q;cin>>q;
            while(q--){
                int l,r;cin>>l>>r;
                cout<<ans[l][r]<<'
    ';
            }
        }
        return 0;
    }
    
    人一我百,人十我万。
  • 相关阅读:
    golang语言特性
    Mysql学习之order by的工作原理
    Mysql聚合函数count(*) 的性能分析
    Mysql的刷脏页问题
    普通索引与唯一索引的选择问题
    Mysql锁的类型与简析
    深入浅出Mysql索引
    Mysql修改语句的运行流程
    Mysql查询语句的运行流程
    Go语言入门之切片的概念
  • 原文地址:https://www.cnblogs.com/AlexPanda/p/12520309.html
Copyright © 2020-2023  润新知