• String & dp Problem Round 3 2017.4.22



      对每一个特征求前缀和,如果它减去前面的某一个地方的和,得到的每个特征是相等的,那么然后就可以更新答案。

      需要解决这个两个问题

      1.如何使答案尽量大?

        这个很简单,直接找尽量靠前的地方就好了。

      2,如何快速查找?

        考虑用后一项减去前一项得到的新的序列,

        然后就可以转换成找一个相等的序列,这个Hash就可以搞定。

    Code

      1 #include<iostream>
      2 #include<fstream>
      3 #include<sstream>
      4 #include<cstdio>
      5 #include<cstring>
      6 #include<set>
      7 #ifndef WIN32
      8 #define Auto "%lld"
      9 #else
     10 #define Auto "%I64d"
     11 #endif
     12 using namespace std;
     13 typedef bool boolean;
     14 #define smin(a, b) (a) = min((a), (b))
     15 #define smax(a, b) (a) = max((a), (b))
     16 
     17 typedef class Feature {
     18     public:
     19         int k;
     20         int lis[35];
     21         
     22         Feature() {        }
     23         Feature(int x, int k):k(k) {
     24             for(int i = 0; i < k; i++)
     25                 if(x & (1 << i))
     26                     lis[i] = 1;
     27                 else
     28                     lis[i] = 0;
     29         }
     30         
     31         friend boolean operator == (Feature& a, Feature& b) {
     32             for(int i = 0; i < a.k; i++)
     33                 if(a.lis[i] != b.lis[i])
     34                     return false;
     35             return true;
     36         }
     37 }Feature;
     38 
     39 template<typename Key, typename Val>
     40 class LinkedNode {
     41     public:
     42         Key key;
     43         Val val;
     44         int next;
     45         LinkedNode()    {        }
     46         LinkedNode(Key key, Val val, int next):key(key), val(val), next(next) {        } 
     47 };
     48 
     49 template<typename Key, typename Val>
     50 class HashMap{
     51     protected:
     52         const static int moder = 500007;
     53         const static int C = 8127;
     54         int hashCode(Feature x) {
     55             int c = 1;
     56             int hash = 0;
     57             for(int i = 0; i < x.k; i++) {
     58                 hash = ((long long)hash + (x.lis[i] * 1LL * c) % moder + moder) % moder;
     59                 c = (c * 1LL * C) % moder;
     60             }
     61             return hash;
     62         }
     63     public:
     64         int cn;
     65         int h[(moder + 1)];
     66         LinkedNode<Key, Val> *lis;
     67         
     68         HashMap():cn(0) {        }
     69         HashMap(int limit):cn(0) {
     70             lis = new LinkedNode<Key, Val>[(const int)(limit + 1)];
     71             memset(h, 0, sizeof(h));
     72         }
     73         
     74         inline void insert(Key& k, Val v) {
     75             int hash = hashCode(k);
     76             lis[++cn] = LinkedNode<Key, Val>(k, v, h[hash]);
     77             h[hash] = cn;
     78         }
     79         
     80         inline Val find(Key& k) {
     81             int hash = hashCode(k);
     82             for(int i = h[hash]; i; i = lis[i].next) {
     83                 if(lis[i].key == k)
     84                     return lis[i].val;
     85             }
     86             return -1;
     87         }
     88 };
     89 
     90 ifstream fin("feature.in");
     91 ofstream fout("feature.out");
     92 
     93 int n, k;
     94 int *a;
     95 
     96 inline void init() {
     97     fin >> n >> k;
     98     a = new int[(const int)(n + 1)];
     99     for(int i = 1; i <= n; i++) {
    100         fin >> a[i];
    101     }
    102 }
    103 
    104 int res = 0;
    105 Feature org;
    106 Feature sumer;
    107 Feature cmp;
    108 HashMap<Feature, int> s;
    109 inline void solve() {
    110     s = HashMap<Feature, int>(n + 5);
    111     org = Feature(0, k - 1);
    112     sumer = Feature(0, k);
    113     cmp.k = k - 1;
    114     s.insert(org, 0);
    115     for(int i = 1; i <= n; i++) {
    116         for(int j = 0; j < k; j++)
    117             if(a[i] & (1 << j))
    118                 sumer.lis[j]++;
    119         for(int j = 0; j < k - 1; j++)
    120             cmp.lis[j] = sumer.lis[j + 1] - sumer.lis[j];
    121         int x = s.find(cmp);
    122         if(x == -1)
    123             s.insert(cmp, i);
    124         else
    125             smax(res, i - x); 
    126     }
    127     fout << res;
    128 }
    129 
    130 int main() {
    131     init();
    132     solve();
    133     return 0;
    134 }


      这个肯定是要Kmp,所以可以考虑Kmp。

      比起朴素的Kmp,多记录一些东西:

      fail[] 在文本串i位置匹配时对应模板串的位置j

      last[] 文本串实际有效的字符所构成的链表,这个记录文本串的位置i的前驱

      对于找到的一个串,沿着last往回找,找到的点打标记,然后把匹配到的位置的下一个last改成这个串的起点的前一个,把当前匹配到的位置改为起点前一个的fail值。

      最后找一遍标记处理一下就可以ac了。

      因为每个字符最多被访问两次(kmp + 打标记),所以总时间复杂度为O(2n + m),其中n为文本串的长度,m为模板串的长度。

    Code

     1 #include<iostream>
     2 #include<fstream>
     3 #include<sstream>
     4 #include<cstdio>
     5 #include<cstring>
     6 #include<set>
     7 #ifndef WIN32
     8 #define Auto "%lld"
     9 #else
    10 #define Auto "%I64d"
    11 #endif
    12 using namespace std;
    13 typedef bool boolean;
    14 #define smin(a, b) (a) = min((a), (b))
    15 #define smax(a, b) (a) = max((a), (b))
    16 
    17 int lenS, lenT;
    18 char T[300005];
    19 char S[300005];
    20 boolean enable[300005];
    21 char newS[300005];
    22 
    23 inline void init() {
    24     scanf("%s", T);
    25     scanf("%s", S);
    26     lenS = strlen(S);
    27     lenT = strlen(T);
    28 }
    29 
    30 int f[300005];
    31 inline void getFail() {
    32     int j = 0;
    33     f[0] = 0;
    34     f[1] = 0;
    35     for(int i = 1; i < lenT; i++) {
    36         j = f[i];
    37         while(j && T[i] != T[j])    j = f[j];
    38         f[i + 1] = (T[i] == T[j]) ? (j + 1) : (0);
    39     }
    40 }
    41 
    42 int fail[300005];
    43 int last[300005];
    44 inline void kmp() {
    45     getFail();
    46     int j = 0;
    47     memset(enable, true, sizeof(boolean) * (lenS + 1));
    48     for(int i = 0; i < lenS; i++)    last[i] = i - 1;
    49     for(int i = 0; i < lenS; i++) {
    50         while(j && S[i] != T[j])    j = f[j];
    51         if(S[i] == T[j])    j++;
    52         fail[i] = j;
    53         if(j == lenT) {
    54             int l = i;
    55             for(int cnt = 0; cnt < lenT; cnt++)
    56                 enable[l] = false, l = last[l];
    57             if(l == -1) j = 0;
    58             else j = fail[l];
    59             last[i + 1] = l;
    60         }
    61     }
    62 }
    63 
    64 inline void solve() {
    65     kmp();
    66     int top = 0;
    67     for(int i = 0; i < lenS; i++) {
    68         if(enable[i])
    69             newS[top++] = S[i];
    70     }
    71     newS[top] = 0;
    72     puts(newS);
    73 }
    74 
    75 int main() {
    76     freopen("sensitive.in", "r", stdin);
    77     freopen("sensitive.out", "w", stdout);
    78     init();
    79     solve();
    80     return 0;
    81 }


      用AC自动机,然后差分数组去优化(虽然没快多少)

    Code

      1 #include<iostream>
      2 #include<fstream>
      3 #include<sstream>
      4 #include<cstdio>
      5 #include<cstring>
      6 #include<set>
      7 #include<queue>
      8 #ifndef WIN32
      9 #define Auto "%lld"
     10 #else
     11 #define Auto "%I64d"
     12 #endif
     13 using namespace std;
     14 typedef bool boolean;
     15 #define smin(a, b) (a) = min((a), (b))
     16 #define smax(a, b) (a) = max((a), (b))
     17 
     18 #define CharSet 26
     19 
     20 typedef class TrieNode {
     21     public:
     22         int val;
     23         TrieNode* next[CharSet];
     24         TrieNode* last;
     25         TrieNode* fail;
     26         TrieNode():val(0), last(NULL), fail(NULL) {
     27             memset(next, 0, sizeof(next));
     28         }
     29 }TrieNode;
     30 
     31 int cti(char x) {
     32     if(x >= 'A' && x <= 'Z')    return x - 'A';
     33     if(x >= 'a' && x <= 'z')     return x - 'a';
     34     return -1;
     35 }
     36 
     37 typedef class Trie {
     38     public:
     39         TrieNode* root;
     40         
     41         Trie() {
     42             root = new TrieNode();
     43         }
     44         
     45         inline void insert(char* s) {
     46             int len = strlen(s);
     47             TrieNode* p = root;
     48             for(int i = 0; i < len; i++) {
     49                 int c = cti(s[i]);
     50                 if(p->next[c] == NULL) {
     51                     p->next[c] = new TrieNode();
     52                 }
     53                 p = p->next[c];
     54             }
     55             p->val = len;
     56         }
     57 }Trie;
     58 
     59 typedef class AhoCorasick {
     60     public:
     61         Trie t;
     62         
     63         inline void insert(char* s) {
     64             t.insert(s);
     65         }
     66         
     67         inline void getFail() {
     68             queue<TrieNode*> que;
     69             t.root->fail = t.root;
     70             for(int i = 0; i < CharSet; i++)
     71                 if(t.root->next[i] != NULL) {
     72                     t.root->next[i]->fail = t.root;
     73                     que.push(t.root->next[i]);
     74                 }
     75             while(!que.empty()) {
     76                 TrieNode* e = que.front();
     77                 que.pop();
     78                 for(int i = 0; i < CharSet; i++) {
     79                     TrieNode* eu = e->next[i];
     80                     if(eu == NULL)    continue;
     81                     TrieNode* f = e->fail;
     82                     while(f != t.root && f->next[i] == NULL)    f = f->fail;      
     83                     eu->fail = (f->next[i]) ? (f->next[i]) : (t.root);
     84                     eu->last = (eu->fail->val) ? (eu->fail) : (eu->fail->last);    
     85                     que.push(eu);
     86                 }
     87             }
     88         }
     89         
     90         int findLast(TrieNode* p) {
     91             if(p) {
     92                 int ret = findLast(p->last);
     93                 return max(p->val, ret);
     94             }
     95             return 0;
     96         }
     97         
     98         inline void change(int* enable, int i, int len) {
     99             enable[i + 1] += -1;
    100             enable[i - len + 1] += 1; 
    101         }
    102         
    103         inline void find(char* s, int* enable) {
    104             int len = strlen(s);
    105             TrieNode* f = t.root;
    106             for(int i = 0; i < len; i++) {
    107                 int c = cti(s[i]);
    108                 if(c == -1) {
    109                     f = t.root;
    110                     continue;
    111                 }
    112                 while(f != t.root && f->next[c] == NULL)    f = f->fail;
    113                 if(f->next[c])    f = f->next[c];
    114                 if(f->val)    change(enable, i, f->val);
    115                 else if(f->last)    change(enable, i, findLast(f->last));
    116             }
    117         }
    118 }AhoCorasick;
    119 
    120 int n;
    121 char s[300005];
    122 int enable[300005];
    123 AhoCorasick ac;
    124 
    125 inline void init() {
    126     scanf("%d", &n);
    127     for(int i = 1; i <= n; i++) {
    128         scanf("%s", s);
    129         ac.insert(s);
    130     }
    131     getchar();
    132     gets(s);
    133 }
    134 
    135 inline void solve() {
    136     int len = strlen(s);
    137     memset(enable, 0, sizeof(boolean) * (len + 1));
    138     ac.getFail();
    139     ac.find(s, enable);
    140     for(int i = 0; i < len; i++) {
    141         if(i) enable[i] += enable[i - 1];
    142         if(enable[i])
    143             s[i] = '*';
    144     }
    145     puts(s);
    146 }
    147 
    148 int main() {
    149     freopen("cleanse.in", "r", stdin);
    150     freopen("cleanse.out", "w", stdout);
    151     init();
    152     solve();
    153     return 0;
    154 }


      通过子串可以想到后缀自动机(虽然标程用的后缀数组,但是我不会QAQ)

      然后上面进行一个拓扑排序,记录根节点(空状态)到每个节点(状态)的总的方案数和经过边权为a的方案数。

      最后把所有的节点的方案数加起来就好了。

    Code

      1 #include<iostream>
      2 #include<fstream>
      3 #include<sstream>
      4 #include<cstdio>
      5 #include<cstring>
      6 #include<set>
      7 #include<queue>
      8 #ifndef WIN32
      9 #define Auto "%lld"
     10 #else
     11 #define Auto "%I64d"
     12 #endif
     13 using namespace std;
     14 typedef bool boolean;
     15 #define smin(a, b) (a) = min((a), (b))
     16 #define smax(a, b) (a) = max((a), (b))
     17 
     18 #define CharSet 26
     19 
     20 int cti(char x) {
     21     return x - 'a';
     22 }
     23 
     24 typedef class TrieNode {
     25     public:
     26         int len;
     27         int dag;
     28         long long cnt;
     29         long long cnta;
     30         TrieNode* next[CharSet];
     31         TrieNode* fail;
     32         TrieNode(int len = 0):fail(NULL), len(len), cnt(0), dag(0), cnta(0) {
     33             memset(next, 0, sizeof(next));
     34         }
     35 }TrieNode;
     36 
     37 typedef class SuffixAutomation {
     38     public:
     39         TrieNode* pool;
     40         TrieNode* top;
     41         TrieNode* root;
     42         TrieNode* last;
     43         
     44         TrieNode* newnode(int len) {
     45             top->len = len;
     46             return top++;;
     47         }
     48         
     49         SuffixAutomation() {        }
     50         SuffixAutomation(int n) {
     51             pool = new TrieNode[(2 * n + 5)];
     52             top = pool;
     53             root = top++;
     54             last = root;
     55         }
     56         
     57         inline void extends(char ch) {
     58             int c = cti(ch);
     59             TrieNode* node = newnode(last->len + 1);
     60             TrieNode* f = last;
     61             while(f && f->next[c] == NULL)
     62                 f->next[c] = node, f = f->fail;
     63             if(!f)    node->fail = root;
     64             else {
     65                 TrieNode* p = f->next[c];
     66                 if(p->len == f->len + 1)
     67                     node->fail = p;
     68                 else {
     69                     TrieNode* q = newnode(f->len + 1);
     70                     memcpy(q->next, p->next, sizeof(q->next)); 
     71                     q->fail = p->fail;
     72                     p->fail = q;
     73                     node->fail = q;
     74                     while(f && f->next[c] == p)
     75                         f->next[c] = q, f = f->fail;
     76                 }
     77             }
     78             last = last->next[c];
     79         }
     80 }SuffixAutomation;
     81 
     82 int n;
     83 char S[100005];
     84 SuffixAutomation sam;
     85 
     86 inline void init() {
     87     gets(S);
     88     n = strlen(S);
     89     sam = SuffixAutomation(n);
     90 }
     91 
     92 void getDag() {
     93     for(TrieNode* p = sam.pool; p != sam.top; p++) {
     94         for(int i = 0; i < CharSet; i++)
     95             if(p->next[i])
     96                 p->next[i]->dag++;
     97     }
     98 }
     99 
    100 queue<TrieNode*> que;
    101 void bfs() {
    102     sam.root->cnt = 1;
    103     que.push(sam.root);
    104     while(!que.empty()) {
    105         TrieNode* e = que.front();
    106         que.pop();
    107         if(e->next[0]) {
    108             e->next[0]->dag--, e->next[0]->cnta += e->cnt, e->next[0]->cnt += e->cnt;
    109             if(!e->next[0]->dag)
    110                 que.push(e->next[0]);
    111         }
    112         for(int i = 1; i < CharSet; i++) {
    113             TrieNode* eu = e->next[i];
    114             if(eu) {
    115                 eu->dag--;
    116                 if(!eu->dag)
    117                     que.push(eu);
    118                 eu->cnt += e->cnt;
    119                 eu->cnta += e->cnta;
    120             }
    121         }
    122     }
    123 }
    124 
    125 long long res = 0;
    126 inline void solve() {
    127     for(int i = 0; i < n; i++)
    128         sam.extends(S[i]);
    129     getDag();
    130     bfs();
    131     for(TrieNode* p = sam.pool; p != sam.top; p++) {
    132         res += p->cnta;
    133     }
    134     printf(Auto, res);
    135 }
    136 
    137 int main() {
    138     freopen("substring.in", "r", stdin);
    139     freopen("substring.out", "w", stdout);
    140     init();
    141     solve();
    142     return 0;
    143 }
  • 相关阅读:
    用例的粒度问题
    REST和RPC最大区别
    成功的结对编程要点
    我认为技术经理应该做的事儿
    敏捷测试实践
    DDD-围绕业务逻辑编程
    依赖反转原则
    Kafka和Rabbitmq的最大区别
    Cassandra快速两次写入导致顺序不对的问题
    DotNetBar之SupergridControl显示图片,行距自动调整
  • 原文地址:https://www.cnblogs.com/yyf0309/p/6748461.html
Copyright © 2020-2023  润新知