zoukankan      html  css  js  c++  java
  • bzoj 1461 字符串匹配

    Bzoj 1461 字符串的匹配
    给两个长度为n、m的序列A、B,问A中有多少个子串与B等价(相同位置的值排名相同)

    题解:同样考虑hash。因为A是子序列,值的排名难以修改,多以用把排名用线段树的位置维护。Hash=sigma(id *base^sort[i]);同样可以比较两串是否相等。注意如果有很多相同值的细节问题:要把他们按位置先后排名

    不过这样因为取模常数过大,bz上很难过

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 #define maxn 500020
      7 #define maxm 10020
      8 #define mod 1000000007
      9 #define __O3 __attribute__((optimize("O3")))
     10 typedef long long LL;
     11 struct node{
     12     int add,ls,rs,sz;
     13     LL hash;
     14 }sgt[maxm * 4];
     15 int tot,n,m,s,root;
     16 int a[maxn],b[maxn],num[maxn],ans,id[maxn],vis[maxn];
     17 LL pow[maxn],Fpow[maxn],hash_b,inv;
     18 const LL p = 31;
     19 
     20 __O3 void pre(){
     21     //memcpy(num,b,sizeof(b));
     22     for (int i = 1 ; i <= m ; i++) num[i] = b[i];
     23     sort(b + 1,b + m + 1);
     24     for (int i = 1 ; i <= m ; i++){
     25         int now = num[i];   
     26         num[i] = lower_bound(b + 1,b + m + 1,num[i]) - b;
     27         num[i] += vis[now];
     28         vis[now]++;
     29     }
     30 }
     31 __O3 void build(int &now,int l,int r){
     32     now = ++tot;
     33     if ( l == r ) return;
     34     int mid = (l + r) >> 1;
     35     build(sgt[now].ls,l,mid);
     36     build(sgt[now].rs,mid + 1,r);
     37 }
     38 __O3 inline void add(int now,int d){
     39     sgt[now].add += d; 
     40     sgt[now].hash = ((sgt[now].hash + (LL) d * (Fpow[sgt[now].sz] - 1)) % mod + mod) % mod;
     41 }
     42 __O3 inline void pushdown(int now){
     43     if ( sgt[now].add != 0 ){
     44         if ( sgt[now].ls ) add(sgt[now].ls,sgt[now].add);
     45         if ( sgt[now].rs ) add(sgt[now].rs,sgt[now].add);
     46         sgt[now].add = 0;
     47     }
     48 }
     49 __O3 inline void update(int now){
     50     sgt[now].sz = sgt[sgt[now].ls].sz + sgt[sgt[now].rs].sz;
     51     sgt[now].hash = (sgt[sgt[now].ls].hash + sgt[sgt[now].rs].hash * pow[sgt[sgt[now].ls].sz]) % mod;
     52 }
     53 //在某个值域上加一个新的位置,或删除一个位置
     54 __O3 void modify(int now,int l,int r,int pos,int d){ //线段树:以值域为位置,每个值域记录在是他的id这和。值域表示的是排名
     55     if ( l == r ){
     56         if ( d < 0 ) sgt[now].sz-- , sgt[now].hash = (((sgt[now].hash + (LL)d * pow[1]) % mod + mod) % mod * inv) % mod;
     57         if ( d > 0 ) sgt[now].sz++ , sgt[now].hash = (sgt[now].hash + (LL)d * pow[sgt[now].sz]) % mod;    
     58         return;
     59     }
     60     pushdown(now);
     61     int mid = (l + r) >> 1;
     62     if ( pos <= mid ) modify(sgt[now].ls,l,mid,pos,d);
     63     else modify(sgt[now].rs,mid + 1,r,pos,d);
     64     update(now);
     65 }
     66 __O3 void modify(int now,int l,int r,int ls,int rs,int d){ //修改位置,将整体左移
     67     if ( ls <= l && rs >= r ){
     68         add(now,d);
     69         return;
     70     }
     71     pushdown(now);
     72     int mid = (l + r) >> 1;
     73     if ( ls <= mid ) modify(sgt[now].ls,l,mid,ls,rs,d);
     74     if ( rs > mid ) modify(sgt[now].rs,mid + 1,r,ls,rs,d);
     75     update(now);
     76 }
     77 __O3 inline LL power(LL x,int y){
     78     LL res = 1;
     79     while ( y ){
     80         if ( y & 1 ) res = (res * x) % mod;
     81         x = (x * x) % mod;
     82         y >>= 1;
     83     }
     84     return res % mod;
     85 }
     86 __O3 void init(){
     87     pre();
     88     pow[0] = Fpow[0] = 1;
     89     for (int i = 1 ; i <= m ; i++) pow[i] = (pow[i - 1] * p) % mod , Fpow[i] = (Fpow[i - 1] + pow[i]) % mod;
     90     inv = power(p,mod - 2);
     91     for (int i = 1 ; i <= m ; i++) hash_b = (hash_b + pow[num[i]] * (LL) i) % mod;
     92     build(root,1,s);
     93     for (int i = 1 ; i <= m ; i++){
     94         modify(root,1,s,a[i],i);
     95     }
     96 }
     97 __O3 int main(){
     98     freopen("match.in","r",stdin);
     99     freopen("match.out","w",stdout);
    100     scanf("%d %d %d",&n,&m,&s);
    101     for (int i = 1 ; i <= n ; i++) scanf("%d",&a[i]);
    102     for (int i = 1 ; i <= m ; i++) scanf("%d",&b[i]);
    103     init();
    104     for (int i = 2 ; i <= n - m + 1 ; i++){
    105         if ( sgt[root].hash == hash_b ) id[++ans] = i - 1;;
    106         modify(root,1,s,a[i - 1],-1);
    107         modify(root,1,s,1,s,-1);
    108         modify(root,1,s,a[i + m - 1],m);
    109     }
    110     if ( sgt[root].hash == hash_b ) id[++ans] = n - m + 1;
    111     printf("%d
    ",ans);
    112     for (int i = 1 ; i <= ans ; i++) printf("%d
    ",id[i]);
    113     return 0;
    114 }
    View Code

    这道题还有一个解法:kmp + 树状数组,对于每个对应的位置,只需要排名相同就可以匹配,直接用树状数组维护有多少个比当前小,有多少个相等,就可以知道当前位置是否相等。显然每个位置都相等,可以推得所有都相等。注意跳fail时两个串要分别进行对应的修改

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 #define maxn 1000020
     5 #define lowbit(x) (x&(-x))
     6 
     7 int s1[maxn],s2[maxn];
     8 int n,m,a[maxn],b[maxn],S,id[maxn],ans,fail[maxn];
     9 
    10 inline int query(int s[],int d){
    11     int ans = 0;
    12     for (int i = d ; i >= 1 ; i -= lowbit(i)) ans += s[i];
    13     return ans;
    14 }
    15 inline void add(int s[],int d,int x){
    16     for (int i = d ; i <= S ; i += lowbit(i)) s[i] += x;
    17 }
    18 inline bool jud(int x,int y){
    19     if ( query(s1,x - 1) == query(s2,y - 1) && query(s1,x) == query(s2,y) ) return 1;
    20     return 0;
    21 }
    22 void getfail(){
    23     int p = 1,q = 0;
    24     while ( p < m ){
    25         if ( !jud(b[p + 1],b[q + 1]) ){
    26             int now = q;
    27                q = fail[q];
    28             for (int i = now ; i > q ; i--){
    29                 add(s2,b[i],-1);    
    30             }
    31             for (int i = p - now + 1 ; i < p - q + 1 ; i++){
    32                 add(s1,b[i],-1);
    33             }        
    34         }
    35         else fail[++p] = ++q , add(s1,b[p],1) , add(s2,b[q],1);
    36         if ( !q && !jud(b[p + 1],b[q + 1]) ) p++;
    37     }
    38 //    for (int i = 1 ; i <= m ; i++) cout<<fail[i]<<" ";
    39 //    cout<<endl;
    40 }
    41 void kmp(){
    42     for (int i = 0 ; i <= S ; i++) s1[i] = s2[i] = 0;
    43     int p = 0,q = 0;
    44     while ( p < n ){
    45         if ( !jud(a[p + 1],b[q + 1]) || q == m ){
    46             int now = q;
    47                q = fail[q];
    48             for (int i = now ; i > q ; i--){
    49                 add(s2,b[i],-1);
    50             }
    51             for (int i = p - now + 1 ; i < p - q + 1 ; i++){
    52                 add(s1,a[i],-1);
    53             }
    54         }
    55         else p++, q++, add(s1,a[p],1), add(s2,b[q],1);
    56         if ( q == m ) id[++ans] = p - m + 1;
    57         if ( !q && !jud(a[p + 1],b[q + 1]) ) p++;
    58     }
    59 }
    60 int main(){
    61     freopen("input.txt","r",stdin);
    62     scanf("%d %d %d",&n,&m,&S);
    63     for (int i = 1 ; i <= n ; i++) scanf("%d",&a[i]);
    64     for (int i = 1 ; i <= m ; i++) scanf("%d",&b[i]);
    65     //b[m + 1] = '#';
    66     getfail();
    67     kmp();
    68     printf("%d
    ",ans);
    69     for (int i = 1 ; i <= ans ; i++) printf("%d
    ",id[i]);
    70     return 0;
    71 }
    View Code

    总结:字符串hash是用来比较字符串的重要方法,可见hash还可以用来比较某些特定意义下的相等:如排名相同即相等。有两种hash方法,一种是一位置为关键字,一种是以排名为关键字。第一种通常实用,但第二种可以在位置比较确定的时候用来比较两个字符串的相对顺序关系。还是要根据题目来定

  • 相关阅读:
    Atitit (Sketch Filter)素描滤镜的实现  图像处理  attilax总结v2
    JS设置cookie、读取cookie、删除cookie
    Atitit 图像处理30大经典算法attilax总结
    Atitit数据库层次架构表与知识点 attilax 总结
    Atitit 游戏的通常流程 attilax 总结 基于cocos2d api
    Atitti css transition Animation differ区别
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 源码实现attilax总结
    Atitit 全屏模式的cs桌面客户端软件gui h5解决方案 Kiosk模式
    Atitit 混合叠加俩张图片的处理 图像处理解决方案 javafx blend
    Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别
  • 原文地址:https://www.cnblogs.com/zqq123/p/5283204.html
Copyright © 2011-2022 走看看