1. 程式人生 > >[NOI2017]蚯蚓排隊 hash

[NOI2017]蚯蚓排隊 hash

題面:洛谷

題解:

  我們暴力維護當前所有隊伍內的所有子串(長度k = 1 ~ 50)的出現次數。

  把每個子串都用一個hash值來表示,每次改變隊伍形態都用雙向連結串列維護,並暴力更新出現次數。

  現在考慮複雜度。

  如果只有連線,沒有斷開,那麼複雜度為不同的子串個數:50n(注意只要O(n)預處理字首和字尾hash就可以做到O(1)得到一個子串的hash值)

  如果有斷開,那麼最多就每斷開一次就對應要再重連一次。所以複雜度最多增加2500 * 斷開次數,而斷開次數1e3....

  所以複雜度就是正確的了。

  此題略卡常。

  如果T了一兩個點,,,就多交幾次吧,,,說不定哪次就過了呢?

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 201000
  5 #define ac 10501000
  6 #define LL long long
  7 #define us unsigned
  8 #define maxn 49//每邊最多49個,以為另外一邊至少一個
  9 #define base 19260817//2333//直接用10???
 10 #define bu 16777215//49999991//100000081//cket 一個質數,,,
11 #define mod 998244353 12 #define h(f) (f & bu) 13 14 int n, m, top; 15 int v[AC], last[AC], Next[AC]; 16 us LL hs[AC], ls[ac], p[ac]; 17 int Head[ac * 3], Next1[ac], date[ac], tot, id; 18 int cnt[ac]; us LL power[ac];//存下每個id對應的hash值以及出現次數 19 int s[AC]; 20 char ss[ac]; 21
//int tot, id; 22 23 #define Next Next1 24 //inline int h(int f){ 25 //return (((f & bu) ^ (mod >> 5)) + 1); 26 //} 27 28 struct node{ 29 30 inline void add(int f, us LL x) 31 {//如果x這個表上沒有k這個值,那就要新開id,否則直接用原來的id 32 // printf("%d %llu\n", f, x); 33 // printf("%llu\n", x); 34 for(R i = Head[f]; i; i = Next[i]) 35 if(power[date[i]] == x) {++ cnt[date[i]]; return ;} 36 int tmp = ++ id; 37 date[++ tot] = tmp, Next[tot] = Head[f], Head[f] = tot; 38 power[tmp] = x, cnt[tmp] = 1; 39 } 40 41 inline void del(int f, us LL x)//找到這個值並刪除一個 42 { 43 for(R i = Head[f]; i; i = Next[i]) 44 if(power[date[i]] == x) {-- cnt[date[i]]; return ;} 45 } 46 47 inline int find(int f, us LL x) 48 { 49 for(R i = Head[f]; i; i = Next[i]) 50 if(power[date[i]] == x) return cnt[date[i]]; 51 return 0; 52 } 53 }T; 54 #undef Next 55 56 inline int read() 57 { 58 int x = 0;char c = getchar(); 59 while(c > '9' || c < '0') c = getchar(); 60 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 61 return x; 62 } 63 64 void pre() 65 { 66 n = read(), m = read(), p[0] = 1; 67 for(R i = 1; i <= n; i ++) v[i] = read(), T.add(h(v[i]), v[i]);//先把單個的加進去 68 for(R i = 1; i <= n; i ++) p[i] = p[i - 1] * base;//自然溢位 69 } 70 71 us LL cal(int l, int r){//返回[l, r]的hash值 72 return ls[r] - ls[l - 1] * p[r - l + 1]; 73 } 74 75 void get_hs(int mid, bool z)//獲取所有長度<= 50的,跨mid的hs值 76 { 77 for(R i = 1; i <= top; i ++) ls[i] = ls[i - 1] * base + s[i]; 78 for(R i = 1; i <= mid; i ++)//列舉開頭 79 { 80 int lim1 = mid - i + 2, lim2 = top - i + 1;//長度要在[lim1, lim2]的範圍內 81 for(R len = lim1; len <= lim2; len ++)//才能保證合法 82 { 83 int r = i + len - 1; 84 us LL x = cal(i, r);//獲取區間hash值 85 if(z) T.add(h(x), x); 86 else T.del(h(x), x); 87 } 88 } 89 } 90 91 void link1()//每次合併的時候暴力加hash值,每次最多增加1250個 92 { 93 int x = read(), y = read(), cnt = 0, tmp = 0;//把j接到i之後 94 Next[x] = y, last[y] = x, top = 0; 95 for(R i = x; i && cnt < maxn; i = last[i]) ++ cnt, tmp = i; 96 for(R i = tmp; i != x; i = Next[i]) s[++ top] = v[i]; 97 s[++ top] = v[x], cnt = top; 98 for(R i = y; i && top - cnt != maxn; i = Next[i]) s[++ top] = v[i]; 99 get_hs(cnt, 1); 100 } 101 102 void link()//每次合併的時候暴力加hash值,每次最多增加1250個 103 { 104 int x = read(), y = read(), cnt = 0, tmp = 0;//把j接到i之後 105 Next[x] = y, last[y] = x, top = 0; 106 for(R i = x; i && cnt < maxn; i = last[i]) ++ cnt, tmp = i; 107 for(R i = tmp; i != x; i = Next[i]) s[++ top] = v[i]; 108 s[++ top] = v[x], cnt = top; 109 for(R i = y; i && top - cnt != maxn; i = Next[i]) s[++ top] = v[i]; 110 get_hs(cnt, 1); 111 } 112 113 void cut()//每次合併的時候暴力減hash值,每次最多減少1250個,但總體很小 114 { 115 int x = read(), y = Next[x], cnt = 0, tmp = 0;//把i和它之後的一個蚯蚓斷開 116 last[y] = Next[x] = top = 0; 117 for(R i = x; i && cnt < maxn; i = last[i]) ++ cnt, tmp = i; 118 for(R i = tmp; i != x; i = Next[i]) s[++ top] = v[i]; 119 s[++ top] = v[x], cnt = top; 120 for(R i = y; i && top - cnt != maxn; i = Next[i]) s[++ top] = v[i]; 121 get_hs(cnt, 0); 122 } 123 124 void find()//處理hash值的時候暴力O(n)處理字首hash值,然後查詢的時候也O(n)遍歷查詢 125 {//因為s長度之和最多1e7.... 126 //cin >> ss + 1, top = strlen(ss + 1); 127 scanf("%s", ss + 1), top = strlen(ss + 1); 128 int k = read(), b = top - k + 1; 129 for(R i = 1; i <= top; i ++) 130 ls[i] = ls[i - 1] * base + ss[i] - '0'; 131 LL ans = 1; 132 for(R i = 1; i <= b; i ++) 133 { 134 us LL x = cal(i, i + k - 1); 135 ans *= T.find(h(x), x); 136 //printf("!!%d ", T.find(x & bu, x)); 137 if(ans > mod) ans %= mod; 138 } 139 //printf("\n"); 140 printf("%lld\n", ans); 141 } 142 143 void work() 144 { 145 for(R i = 1; i <= m; i ++) 146 { 147 int opt = read(); 148 if(opt == 1) link(); 149 else if(opt == 2) cut(); 150 else find(); 151 } 152 } 153 154 int main() 155 { 156 // freopen("in.in", "r", stdin); 157 pre(); 158 work(); 159 //fclose(stdin); 160 return 0; 161 }
View Code