• [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
    ", f, x);
     33     //    printf("%llu
    ", 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("
    ");
    140     printf("%lld
    ", 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
  • 相关阅读:
    Scanner和BufferedReader
    java annotation
    java获取短uuid
    定时任务线程
    sql 查询最近30分钟或者自定义时间数据
    查看base64编码图片
    oracle 的PACKAGE恢复过程
    Oracle BFILE备忘
    读取Spring的配置文件applicationContext.xml的5种方法
    解决eclipse ctrl+鼠标左键不能用
  • 原文地址:https://www.cnblogs.com/ww3113306/p/10067798.html
Copyright © 2020-2023  润新知