1. 程式人生 > >計蒜客 UCloud 的安全秘鑰 ——(hash)

計蒜客 UCloud 的安全秘鑰 ——(hash)

pan ref namespace mes 能夠 targe com print lower

  題目鏈接:https://nanti.jisuanke.com/t/15769。

  題意是求可以變換位置以後相同的子串有多少個,那麽做法是只要每個數字的平方和,立方和以及四次方和都相同就可以了。

  代碼如下:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <map>
 5 using namespace std;
 6 typedef long long LL;
 7 typedef pair <LL, LL> PII;
8 const int N = 5e4 + 5; 9 const int M = 1e5 + 5; 10 const int DX = 3; 11 int n, m; 12 LL s[N], pre2[N], pre3[N], pre4[N]; 13 int vism[M]; 14 int mp[M]; 15 LL mm2[M], mm3[M], mm4[M]; 16 int len[M]; 17 LL nn[655][N]; 18 int tot; 19 int main(){ 20 scanf("%d", &n); 21 for(int i = 1; i <= n; ++ i){
22 scanf("%lld", &s[i]); 23 pre2[i] = pre2[i-1] + s[i]*s[i]; 24 pre3[i] = pre3[i-1] + s[i]*s[i]*s[i]; 25 pre4[i] = pre4[i-1] + s[i]*s[i]*s[i]*s[i]; 26 } 27 scanf("%d", &m); 28 LL t; 29 for(int i = 1; i <= m; ++ i){ 30 scanf("%d", &len[i]);
31 vism[len[i]] = 1; 32 for(int j = 0; j < len[i]; ++ j){ 33 scanf("%lld", &t); 34 mm2[i] += t*t; 35 mm3[i] += t*t*t; 36 mm4[i] += t*t*t*t; 37 } 38 } 39 for(int i = 1; i < M; ++ i){ 40 if(vism[i]){ 41 for(int j = i; j <= n; ++ j){ 42 nn[tot][j-i] = (((pre4[j] - pre4[j-i]) << DX) << DX) + ((pre3[j] - pre3[j-i]) << DX) + (pre2[j] - pre2[j-i]); 43 } 44 sort(nn[tot], nn[tot] + n-i+1); 45 mp[i] = tot ++; 46 } 47 } 48 LL tmp, p; 49 for(int i = 1; i <= m; ++ i){ 50 tmp = ((mm4[i] << DX) << DX) + (mm3[i] << DX) + mm2[i]; 51 p = mp[len[i]]; 52 printf("%d\n", upper_bound(nn[p], nn[p]+n-len[i]+1, tmp) - lower_bound(nn[p], nn[p]+n-len[i]+1, tmp)); 53 } 54 }

  需要註意的是,所有串的長度不超過2e5,那麽tot的個數不會太多,因為不同長度種類的個數從1開始,那麽到不了幾百,他們的累和就會超過2e5,因此,以上算法在時間和空間上都能夠承受。同時需要註意的是,倉鼠說這題卡map,因此用sort過。

計蒜客 UCloud 的安全秘鑰 ——(hash)