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 }
posted @ 2017-04-22 17:37  阿波罗2003  阅读(207)  评论(0编辑  收藏  举报