首页 > 其他分享 >销售基因链 题解

销售基因链 题解

时间:2023-08-28 09:34:55浏览次数:42  
标签:int 题解 基因 st v3 v4 bitset 哈希 销售

销售基因链

题目大意

给定 \(n\) 个字符串,长度总和为 \(m\),进行 \(q\) 次询问,每次询问给定两个字符串 \(p,s\),问所有的字符串中以 \(p\) 为前缀且以 \(s\) 为后缀的有多少个。

思路分析

分享一个船新的答辩做法。(目前是最劣解)

考虑哈希,对每个给定的字符串前后各做一遍哈希,将所有的哈希值离散化,对每个字符串往其对应的所有哈希值的 vector 中存入自己的编号。

那么我们的问题就变成了:

  • 给定 \(m\) 个集合,集合中数的总和在 \(O(m)\) 数量级,进行 \(q\) 次询问,每次询问两个集合的交集的元素个数。

这个问题可以通过 bitset 解决。

简单的说,我们可以对每个哈希值建一个 bitset,每次求交集的时候只需要与一下对应的 bitset 再求一下元素个数就可以了,单次时间复杂度为 \(O(\frac{nm}{w})\),可以接受。

但空间复杂度无法接受,因此我们考虑根号分治平衡时空复杂度。

具体的说,我们设定一个阈值 \(B\),只对所有元素个数大于 \(B\) 的哈希值建立 bitset。查询时,对元素个数小于 \(B\) 的集合直接暴力扫描加入一个公用的 bitset,再与另一个 bitset 与一下,最后将公用的 bitset 清空。

这样我们的时间复杂度就为:\(O(qB+\frac{nq}{w}+m\log m)\),空间复杂度为 \(O(\frac{nm}{vB})\),其中 \(w=64,v=8\),时空都还可以接受。

于是你满怀希望的交了一发,取得了 \(35\text{pts}\) 的好成绩,最大点跑了 \(6s\)。

开始大力卡常:

  • 将哈希值离散化的 map 换成排序加去重加 lower_bound,时间降为 \(4.5s\)。

  • unsigned long long 自然溢出哈希改为 unsigned int 自然溢出哈希,时间降为 \(4s\)。

  • 加字符串快读快写,时间降为 \(3.5s\)。

  • 将固定阈值 \(B=1000\) 改为 \(B=\sqrt {q}\),时间降为 \(3s\)。

  • 在查询时先判断哈希值存不存在,时间降为 \(2s\)。

  • 将前哈希和后哈希分开,各自独立离散化,时间降为 \(1.5s\)。

这样,我们就以

的好成绩喜提最劣解通过本题。

代码

(最劣解的代码也要看?)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#include <vector>
#include <cmath>

using namespace std;
const int M=5010,L=100010,N=2000100,P=133,Q=133;
typedef unsigned int ull;

int n,m,tt,tt2,cnt,tot1,tot2,BL,sum;
int vis1[N<<1],vis2[N<<1];
ull v3[N],v4[N],vHash1[N],vHash2[N];
int vid1[N],vid2[N];

vector<int> v1[N<<1],v2[N<<1];
bitset<L> bset[M];
char s[N],s1[N],s2[N];

#define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<16,stdin),S==T)?EOF:*S++)
char B[1<<16],*S=B,*T=B;

inline void readint(int &x){
    x=0;char ch=getchar();
    while(ch<'0'||'9'<ch) ch=getchar();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar();
}

inline int readchar(char a[]){
    int len=0;
    char ch=getchar();
    while(ch<'A'&&'Z'<ch) ch=getchar();
    while('A'<=ch&&ch<='Z') a[++len]=ch,ch=getchar();
    return len;
}

void write(int x){
    int k=x/10;
    if(k) write(k);
    putchar(x%10+'0');
}

int main(){
    readint(n);readint(m);
    for(int i=1;i<=n;i++){
        int len=readchar(s);
        sum+=len;
        ull Hash=1;
        for(int j=1;j<=len;j++){
            Hash=Hash*P+s[j]+Q;
            v3[++tt]=Hash;tot1++;
            vHash1[tot1]=Hash;vid1[tot1]=i;
        }
        Hash=1;
        for(int j=len;j>=1;j--){
            Hash=Hash*P+s[j]+Q;
            v4[++tt2]=Hash;tot2++;
            vHash2[tot2]=Hash;vid2[tot2]=i;
        }
    }   
    BL=pow(m,0.5);
    sort(v3+1,v3+tt+1);sort(v4+1,v4+tt2+1);
    tt=unique(v3+1,v3+tt+1)-v3-1;
    tt2=unique(v4+1,v4+tt2+1)-v4-1;
    for(int i=1;i<=tot1;i++)
        v1[lower_bound(v3+1,v3+tt+1,vHash1[i])-v3].push_back(vid1[i]);
    for(int i=1;i<=tot2;i++)
        v2[lower_bound(v4+1,v4+tt2+1,vHash2[i])-v4].push_back(vid2[i]);
    for(int i=1;i<=tt;i++)
        if(v1[i].size()>BL){
            vis1[i]=++cnt;
            for(int j=0;j<v1[i].size();j++) bset[cnt][v1[i][j]]=1;
        }
    for(int i=1;i<=tt2;i++)
        if(v2[i].size()>BL){
            vis2[i]=++cnt;
            for(int j=0;j<v2[i].size();j++) bset[cnt][v2[i][j]]=1;
        }
    while(m--){
        int len1=readchar(s1);
        int len2=readchar(s2);
        ull Hash1=1,Hash2=1;
        for(int i=1;i<=len1;i++)
            Hash1=Hash1*P+s1[i]+Q;
        for(int i=len2;i>=1;i--)
            Hash2=Hash2*P+s2[i]+Q;
        int x=lower_bound(v3+1,v3+tt+1,Hash1)-v3;
        int y=lower_bound(v4+1,v4+tt2+1,Hash2)-v4;
        if(v3[x]!=Hash1||v4[y]!=Hash2){cout<<"0\n";continue;}
        if(v1[x].size()>BL&&v2[y].size()>BL){
            write((bset[vis1[x]]&bset[vis2[y]]).count());putchar('\n');
        }
        else if(v1[x].size()>BL||v2[y].size()>BL){
            if(v1[x].size()>BL){
                bitset<L> st;
                for(auto it:v2[y]) st[it]=1;
                write((st&bset[vis1[x]]).count());putchar('\n');
            }
            else{
                bitset<L> st;
                for(auto it:v1[x]) st[it]=1;
                write((st&bset[vis2[y]]).count());putchar('\n');
            }
        }
        else{
            bitset<L> st,st2;
            for(auto it:v1[x]) st[it]=1;
            for(auto it:v2[y]) st2[it]=1;
            write((st&st2).count());putchar('\n');
        }
    }
    return 0;
}

标签:int,题解,基因,st,v3,v4,bitset,哈希,销售
From: https://www.cnblogs.com/TKXZ133/p/17661420.html

相关文章

  • P2486 [SDOI2011] 染色 题解
    P2486[SDOI2011]染色神仙树剖题。题意给你一棵树,每个点都有颜色,支持下面两种操作:路径染色。路径颜色段数量查询。树剖部分我们看到树上问题,不好处理,所以想办法给他树剖搞一搞,给他转化成序列的操作。我们树剖就是正常的树剖,然后我们考虑如何维护这个颜色序列。我......
  • P9585 酒店题解
    分析:贪心算法。有\(n\)个客人。对于每一位客人,我们都要遍历一遍所有房间,找出最优入住房间编号。设当前遍历的房间编号为\(j\)。分三种情况:左右两边的房间皆空,则为最优房间。左右两边只有一个房间有客人,则愤怒值加\(2\)(因为有两个客人所以加\(2\))。左右两边都有人住,则......
  • ABC317F题解
    让人头大的数位DP。建议评蓝。个人认为不适合放ABC的F。将三个数二进制拆分,使三个数异或为0相当于每个二进制位三个数中有0或2个是1。所以考虑数位DP,设\(dp[i][m1][m2][m3][lim1][lim2][lim3]\)为第\(i\)位,三个数模\(a\),\(b\),\(c\)分别是\(m1\),\(m2\),\(m3\)......
  • NOIP2013提高组初赛易错题解析
    7. 正解:可以画出递归树,画出后应该是这样子的 画出递归树,就可以得出答案时间复杂度为O(Fn) 15. 正解:2T(n/2)=O(logn)T(n)=2*T(n/2)+2*n=O(nlogn)三.2. 错误原因:蒙的正解:通过观察,可以找到递推关系式,f[n]=1/n*(n+f[1]+f[2]+...+f[n]),f[1]=0,f[2]=2,经过计算......
  • NOIP2017提高组初赛易错题解析
     8.由四个不同的点构成的简单无向连通图的个数是()A.32 B.35 C.38 D.41错误原因:数重了正解:分情况计算,6条边的有1种,5条边的有C(6,1)=6种,4条边的有C(6,4)=15种,3条边,要分度数,2+2+1+1的有12种,3+1+1+1的有4种,共38种 10.若 f0​=0,f1​=1,fn+1​=(fn​+fn−1)/2​​,则随着......
  • NOIP2016提高组初赛易错题解析
    9. 正解:每一个bit,都有两种可能,0和1,所以最多可以使用232=4GB的内存 14. 正解:使用代入法,T(n)=2T(n/4)+sqrt(n),T(n/16)=2T(n/4/4/4)+1/4*sqrt(n),T(n)=2k+k*sqrt(n)=sqrt(n)+k*sqrt(n),则时间复杂度为O(sqrt(n)logn) 二.1. 正解:前三个都是无线通信技术,以太网是有......
  • NOIP2018提高组初赛易错题解析
    2.下列属于解释执行的程序设计语言是()A.C B.C++ C.Pascal D.Python错误原因:忘记了正解:C、C++和Pascal都是编译性语言,而Python是解释性语言 5.设某算法的时间复杂度函数的递推方程是 T(n)=T(n-1)+n(n 为正整数)及 T(0)=1,则该算法的时间复杂度为()A.O(logn) ......
  • P7414 [USACO21FEB] Modern Art 3 G 题解
    思路考虑区间DP。设\(f_{i,j}\)表示要刷到\([i,j]\)这一段的目标需要的最小次数。对于\(f_{i,j}\),如果\(color_i\)与\(color_j\)相等,那么再子区间合并的时候就可以少刷一次,即\(f_{i,j}=\min\limits_{k=i}^{j-1}f_{i,k}+f_{k+1,j}-1\)。否则\(f......
  • CSP-J2022初赛易错题解析
    7.假设字母表{a,b,c,d,e}在字符串出现的频率分别为10%,15%,30%,16%,29%。若使用哈夫曼编码方式对字母进行不定长的二进制编码,字母d的编码长度()位。A.1  B.2 C.2或3  D.3正解:画出哈夫曼树即可9.考虑由N个顶点构成的有向连通图,采用邻接矩阵的数据结构表示时,该矩阵中至......
  • CSP-J2020初赛易错题解析
    一.5. 正解:冒泡排序最少比较n-1次,即单调上升序列 10.5 个小朋友并排站成一列,其中有两个小朋友是双胞胎,如果要求这两个双胞胎必须相邻,则有()种不同排列方法?A.24 B.36 C.72 D.48错误原因:忘记乘上A(2,2)了正解:捆绑法,A(4,4)*A(2,2)=48 15.有五副不同颜色的手套(......