• codeforecs 316G2 哈希+优化


    https://codeforces.com/contest/316/problem/G2

    给定一个母串$s$,问母串$s$有多少本质不同的子串$t$是“好”的。

      一个字符串$t$是好的,仅当$t$满足了所有的$n$个条件。

      第$i$个条件用一个三元组$(p_i,L_i,R_i)$来描述。

      其中$p_i$为一个字符串,$L_i,R_i$为整数,且$L_ileq R_i$。

      仅当字符串$t$在$p_i$中出现次数在$L_i$到$R_i$之间时,它是"好"的。

      $|s|,|p_i|leq 2 imes 10^3,nleq 10$

    专门说一下G2吧,G2感觉是裸哈希+暴力,一眼复杂度$O(n*(|s|^2+sum|p|^2)*hashmap)$

    但是ac过程十分艰苦,首先,如果是单哈希$mod1e9+7$,基本上肯定会碰撞导致wa

    (1e9的哈希空间,基本上1e6次访问就能发生上百次碰撞)

    然后换成ull单哈希,感谢cf爸爸不卡ull.

    但是还是T,

    然后换成u_map和u_set,但是还是T

    然后加入优化

    1.如果枚举的p的子串长度>s的长度,break

    2.枚举p子串起点,再枚举p子串终点,如果当前p的子串不存在于s中,break,后面的必不存在(和上面的其实重复了)

    3.从枚举s的子串改为枚举p的子串(这个实际上应该没快多少)

    4.开两个set保存s满足前i个限制的子串,每次滚动指针,s1,s2,

    其中s1保存了当前满足前i个限制的所有子串

    如果当前限制l==0,那么枚举p的所有子串,所有出现次数>r的,从s1中删除,然后暂时不交换指针

    如果当前限制l>0,那么枚举p的所有子串,只把出现次数满足约数的放入s2,然后交换s1,s2指针

    以上的优化其实都挺片面,感谢cf爸爸不卡之恩

    #include<bits/stdc++.h>
    #define ull unsigned long long
    #define fi first
    #define se second
    #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    #define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
    using namespace std;//head
    const int maxn=2e3+10,maxm=1e3+10;
    int n,m;
    const ull decm=131;
    ull pw[maxn];
    void init(int n=maxn-5){pw[0]=1;rep(i,1,n) pw[i]=pw[i-1]*decm;}
    class strhash{public:
      ull hs[maxn],len;
      void calhs(char *s,int n){len=n;rep(i,0,len-1)hs[i+1]=hs[i]*decm+s[i];}
      inline ull geths(int a,int b){return hs[b]-hs[a-1]*pw[b-a+1];}
    }mps;
    unordered_map<ull,int> cnt;
    unordered_set<ull> vis,s1,s2;
    char s[maxn];
    int l,r;
    int main() {IO;
      init(maxn-5);cin>>s>>n;
      m=strlen(s);mps.calhs(s,m);
      rep(i,1,m)rep(j,i,m) {
        ull x=mps.geths(i,j);
        if(!vis.count(x)){
          vis.insert(x);
          s1.insert(x);
        }
      }
      if(n==0){
        cout<<vis.size();
        return 0;
      }
      int ans=0;
      unordered_set<ull> &sub=s1,&tmp=s2;
      rep(i,1,n){
        cin>>s>>l>>r;
        int len=strlen(s);cnt.clear();
        mps.calhs(s,len);
        rep(j,1,len)rep(k,j,len) {
          if(k-j+1>m) break;
          ull x=mps.geths(j,k);
          if(!vis.count(x)) break;
          cnt[x]++;
        }
        if(l==0){
          for(auto x:cnt)if(sub.count(x.fi)&&x.se>r)sub.erase(x.fi);
          if(i==n)ans=sub.size();
          continue;
        }
        for(auto x:cnt)if(sub.count(x.fi)&&x.se>=l&&x.se<=r)tmp.insert(x.fi);
        sub.clear();
        if(i==n)ans=tmp.size();
        swap(tmp,sub);
      }
      cout<<ans<<endl;
    }
    
  • 相关阅读:
    leetcode 对称二叉树
    leetcode 验证二叉搜索树
    蓝桥杯 完美的代价 贪心
    蓝桥杯 字符串对比 模拟
    蓝桥杯 芯片测试 极限找规律
    蓝桥杯 2n皇后问题 深搜
    74. 搜索二维矩阵
    二分 34
    二分 35
    二分 69
  • 原文地址:https://www.cnblogs.com/nervendnig/p/11358980.html
Copyright © 2020-2023  润新知