判断两个可重集是否相同,给每个元素一个随机的 64 位无符号整数权值,然后全部加起来作为集合的 Hash 值。那么一个子串的 Hash 值可以简单地由前缀和作差得到,每次检验的复杂度为O(1)。
其实只要一个观察 询问中不同的长度只有 O(l√en) 种 map竟然T了 smg
#include<cstdio> #include<cstdlib> #include<algorithm> #include<map> #define pb push_back using namespace std; typedef unsigned long long ull; typedef pair<ull,int> abcd; #define read(x) scanf("%d",&(x)) const int N=200005; int n,m,s[N]; ull a[N],H[N]; vector<abcd> v[N]; int ans[N]; const int _P=1000007; const int _N=1000005; struct HashMap{ int head[_P],inum,clk; int tag[_P]; ull h[_N]; int g[_N],next[_N]; void _new(){ ++clk; inum=0; } int Head(int x){ return tag[x]!=clk?(tag[x]=clk,head[x]=0):head[x]; } int &at(ull _h){ int hs=_h*233%_P; for (int p=Head(hs);p;p=next[p]) if (h[p]==_h) return g[p]; h[++inum]=_h; g[inum]=0; next[inum]=head[hs]; head[hs]=inum; return g[inum]; } }Map; int main(){ srand(10086); freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); for (int i=1;i<=n;i++) a[i]=((ull)rand()<<32)+rand(); for (int i=1;i<=n;i++) read(s[i]),H[i]=H[i-1]+a[s[i]]; read(m); for (int i=1;i<=m;i++){ int k,x; ull h=0; read(k); for (int j=1;j<=k;j++) read(x),h=h+a[x]; v[k].pb(abcd(h,i)); } for (int i=1;i<=n;i++) if (v[i].size()){ sort(v[i].begin(),v[i].end()); Map._new(); for (int j=1;j+i-1<=n;j++) Map.at(H[j+i-1]-H[j-1])++; for (int j=0;j<v[i].size();j++) ans[v[i][j].second]=Map.at(v[i][j].first); } for (int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }