String & dp Problem Round 3 2017.4.22
对每一个特征求前缀和,如果它减去前面的某一个地方的和,得到的每个特征是相等的,那么然后就可以更新答案。
需要解决这个两个问题
1.如何使答案尽量大?
这个很简单,直接找尽量靠前的地方就好了。
2,如何快速查找?
考虑用后一项减去前一项得到的新的序列,
然后就可以转换成找一个相等的序列,这个Hash就可以搞定。
Code
- #include<iostream>
- #include<fstream>
- #include<sstream>
- #include<cstdio>
- #include<cstring>
- #include<set>
- #ifndef WIN32
- #define Auto "%lld"
- #else
- #define Auto "%I64d"
- #endif
- using namespace std;
- typedef bool boolean;
- #define smin(a, b) (a) = min((a), (b))
- #define smax(a, b) (a) = max((a), (b))
- typedef class Feature {
- public:
- int k;
- int lis[];
- Feature() { }
- Feature(int x, int k):k(k) {
- for(int i = ; i < k; i++)
- if(x & ( << i))
- lis[i] = ;
- else
- lis[i] = ;
- }
- friend boolean operator == (Feature& a, Feature& b) {
- for(int i = ; i < a.k; i++)
- if(a.lis[i] != b.lis[i])
- return false;
- return true;
- }
- }Feature;
- template<typename Key, typename Val>
- class LinkedNode {
- public:
- Key key;
- Val val;
- int next;
- LinkedNode() { }
- LinkedNode(Key key, Val val, int next):key(key), val(val), next(next) { }
- };
- template<typename Key, typename Val>
- class HashMap{
- protected:
- const static int moder = ;
- const static int C = ;
- int hashCode(Feature x) {
- int c = ;
- int hash = ;
- for(int i = ; i < x.k; i++) {
- hash = ((long long)hash + (x.lis[i] * 1LL * c) % moder + moder) % moder;
- c = (c * 1LL * C) % moder;
- }
- return hash;
- }
- public:
- int cn;
- int h[(moder + )];
- LinkedNode<Key, Val> *lis;
- HashMap():cn() { }
- HashMap(int limit):cn() {
- lis = new LinkedNode<Key, Val>[(const int)(limit + )];
- memset(h, , sizeof(h));
- }
- inline void insert(Key& k, Val v) {
- int hash = hashCode(k);
- lis[++cn] = LinkedNode<Key, Val>(k, v, h[hash]);
- h[hash] = cn;
- }
- inline Val find(Key& k) {
- int hash = hashCode(k);
- for(int i = h[hash]; i; i = lis[i].next) {
- if(lis[i].key == k)
- return lis[i].val;
- }
- return -;
- }
- };
- ifstream fin("feature.in");
- ofstream fout("feature.out");
- int n, k;
- int *a;
- inline void init() {
- fin >> n >> k;
- a = new int[(const int)(n + )];
- for(int i = ; i <= n; i++) {
- fin >> a[i];
- }
- }
- int res = ;
- Feature org;
- Feature sumer;
- Feature cmp;
- HashMap<Feature, int> s;
- inline void solve() {
- s = HashMap<Feature, int>(n + );
- org = Feature(, k - );
- sumer = Feature(, k);
- cmp.k = k - ;
- s.insert(org, );
- for(int i = ; i <= n; i++) {
- for(int j = ; j < k; j++)
- if(a[i] & ( << j))
- sumer.lis[j]++;
- for(int j = ; j < k - ; j++)
- cmp.lis[j] = sumer.lis[j + ] - sumer.lis[j];
- int x = s.find(cmp);
- if(x == -)
- s.insert(cmp, i);
- else
- smax(res, i - x);
- }
- fout << res;
- }
- int main() {
- init();
- solve();
- return ;
- }
这个肯定是要Kmp,所以可以考虑Kmp。
比起朴素的Kmp,多记录一些东西:
fail[] 在文本串i位置匹配时对应模板串的位置j
last[] 文本串实际有效的字符所构成的链表,这个记录文本串的位置i的前驱
对于找到的一个串,沿着last往回找,找到的点打标记,然后把匹配到的位置的下一个last改成这个串的起点的前一个,把当前匹配到的位置改为起点前一个的fail值。
最后找一遍标记处理一下就可以ac了。
因为每个字符最多被访问两次(kmp + 打标记),所以总时间复杂度为O(2n + m),其中n为文本串的长度,m为模板串的长度。
Code
- #include<iostream>
- #include<fstream>
- #include<sstream>
- #include<cstdio>
- #include<cstring>
- #include<set>
- #ifndef WIN32
- #define Auto "%lld"
- #else
- #define Auto "%I64d"
- #endif
- using namespace std;
- typedef bool boolean;
- #define smin(a, b) (a) = min((a), (b))
- #define smax(a, b) (a) = max((a), (b))
- int lenS, lenT;
- char T[];
- char S[];
- boolean enable[];
- char newS[];
- inline void init() {
- scanf("%s", T);
- scanf("%s", S);
- lenS = strlen(S);
- lenT = strlen(T);
- }
- int f[];
- inline void getFail() {
- int j = ;
- f[] = ;
- f[] = ;
- for(int i = ; i < lenT; i++) {
- j = f[i];
- while(j && T[i] != T[j]) j = f[j];
- f[i + ] = (T[i] == T[j]) ? (j + ) : ();
- }
- }
- int fail[];
- int last[];
- inline void kmp() {
- getFail();
- int j = ;
- memset(enable, true, sizeof(boolean) * (lenS + ));
- for(int i = ; i < lenS; i++) last[i] = i - ;
- for(int i = ; i < lenS; i++) {
- while(j && S[i] != T[j]) j = f[j];
- if(S[i] == T[j]) j++;
- fail[i] = j;
- if(j == lenT) {
- int l = i;
- for(int cnt = ; cnt < lenT; cnt++)
- enable[l] = false, l = last[l];
- if(l == -) j = ;
- else j = fail[l];
- last[i + ] = l;
- }
- }
- }
- inline void solve() {
- kmp();
- int top = ;
- for(int i = ; i < lenS; i++) {
- if(enable[i])
- newS[top++] = S[i];
- }
- newS[top] = ;
- puts(newS);
- }
- int main() {
- freopen("sensitive.in", "r", stdin);
- freopen("sensitive.out", "w", stdout);
- init();
- solve();
- return ;
- }
用AC自动机,然后差分数组去优化(虽然没快多少)
Code
- #include<iostream>
- #include<fstream>
- #include<sstream>
- #include<cstdio>
- #include<cstring>
- #include<set>
- #include<queue>
- #ifndef WIN32
- #define Auto "%lld"
- #else
- #define Auto "%I64d"
- #endif
- using namespace std;
- typedef bool boolean;
- #define smin(a, b) (a) = min((a), (b))
- #define smax(a, b) (a) = max((a), (b))
- #define CharSet 26
- typedef class TrieNode {
- public:
- int val;
- TrieNode* next[CharSet];
- TrieNode* last;
- TrieNode* fail;
- TrieNode():val(), last(NULL), fail(NULL) {
- memset(next, , sizeof(next));
- }
- }TrieNode;
- int cti(char x) {
- if(x >= 'A' && x <= 'Z') return x - 'A';
- if(x >= 'a' && x <= 'z') return x - 'a';
- return -;
- }
- typedef class Trie {
- public:
- TrieNode* root;
- Trie() {
- root = new TrieNode();
- }
- inline void insert(char* s) {
- int len = strlen(s);
- TrieNode* p = root;
- for(int i = ; i < len; i++) {
- int c = cti(s[i]);
- if(p->next[c] == NULL) {
- p->next[c] = new TrieNode();
- }
- p = p->next[c];
- }
- p->val = len;
- }
- }Trie;
- typedef class AhoCorasick {
- public:
- Trie t;
- inline void insert(char* s) {
- t.insert(s);
- }
- inline void getFail() {
- queue<TrieNode*> que;
- t.root->fail = t.root;
- for(int i = ; i < CharSet; i++)
- if(t.root->next[i] != NULL) {
- t.root->next[i]->fail = t.root;
- que.push(t.root->next[i]);
- }
- while(!que.empty()) {
- TrieNode* e = que.front();
- que.pop();
- for(int i = ; i < CharSet; i++) {
- TrieNode* eu = e->next[i];
- if(eu == NULL) continue;
- TrieNode* f = e->fail;
- while(f != t.root && f->next[i] == NULL) f = f->fail;
- eu->fail = (f->next[i]) ? (f->next[i]) : (t.root);
- eu->last = (eu->fail->val) ? (eu->fail) : (eu->fail->last);
- que.push(eu);
- }
- }
- }
- int findLast(TrieNode* p) {
- if(p) {
- int ret = findLast(p->last);
- return max(p->val, ret);
- }
- return ;
- }
- inline void change(int* enable, int i, int len) {
- enable[i + ] += -;
- enable[i - len + ] += ;
- }
- inline void find(char* s, int* enable) {
- int len = strlen(s);
- TrieNode* f = t.root;
- for(int i = ; i < len; i++) {
- int c = cti(s[i]);
- if(c == -) {
- f = t.root;
- continue;
- }
- while(f != t.root && f->next[c] == NULL) f = f->fail;
- if(f->next[c]) f = f->next[c];
- if(f->val) change(enable, i, f->val);
- else if(f->last) change(enable, i, findLast(f->last));
- }
- }
- }AhoCorasick;
- int n;
- char s[];
- int enable[];
- AhoCorasick ac;
- inline void init() {
- scanf("%d", &n);
- for(int i = ; i <= n; i++) {
- scanf("%s", s);
- ac.insert(s);
- }
- getchar();
- gets(s);
- }
- inline void solve() {
- int len = strlen(s);
- memset(enable, , sizeof(boolean) * (len + ));
- ac.getFail();
- ac.find(s, enable);
- for(int i = ; i < len; i++) {
- if(i) enable[i] += enable[i - ];
- if(enable[i])
- s[i] = '*';
- }
- puts(s);
- }
- int main() {
- freopen("cleanse.in", "r", stdin);
- freopen("cleanse.out", "w", stdout);
- init();
- solve();
- return ;
- }
通过子串可以想到后缀自动机(虽然标程用的后缀数组,但是我不会QAQ)
然后上面进行一个拓扑排序,记录根节点(空状态)到每个节点(状态)的总的方案数和经过边权为a的方案数。
最后把所有的节点的方案数加起来就好了。
Code
- #include<iostream>
- #include<fstream>
- #include<sstream>
- #include<cstdio>
- #include<cstring>
- #include<set>
- #include<queue>
- #ifndef WIN32
- #define Auto "%lld"
- #else
- #define Auto "%I64d"
- #endif
- using namespace std;
- typedef bool boolean;
- #define smin(a, b) (a) = min((a), (b))
- #define smax(a, b) (a) = max((a), (b))
- #define CharSet 26
- int cti(char x) {
- return x - 'a';
- }
- typedef class TrieNode {
- public:
- int len;
- int dag;
- long long cnt;
- long long cnta;
- TrieNode* next[CharSet];
- TrieNode* fail;
- TrieNode(int len = ):fail(NULL), len(len), cnt(), dag(), cnta() {
- memset(next, , sizeof(next));
- }
- }TrieNode;
- typedef class SuffixAutomation {
- public:
- TrieNode* pool;
- TrieNode* top;
- TrieNode* root;
- TrieNode* last;
- TrieNode* newnode(int len) {
- top->len = len;
- return top++;;
- }
- SuffixAutomation() { }
- SuffixAutomation(int n) {
- pool = new TrieNode[( * n + )];
- top = pool;
- root = top++;
- last = root;
- }
- inline void extends(char ch) {
- int c = cti(ch);
- TrieNode* node = newnode(last->len + );
- TrieNode* f = last;
- while(f && f->next[c] == NULL)
- f->next[c] = node, f = f->fail;
- if(!f) node->fail = root;
- else {
- TrieNode* p = f->next[c];
- if(p->len == f->len + )
- node->fail = p;
- else {
- TrieNode* q = newnode(f->len + );
- memcpy(q->next, p->next, sizeof(q->next));
- q->fail = p->fail;
- p->fail = q;
- node->fail = q;
- while(f && f->next[c] == p)
- f->next[c] = q, f = f->fail;
- }
- }
- last = last->next[c];
- }
- }SuffixAutomation;
- int n;
- char S[];
- SuffixAutomation sam;
- inline void init() {
- gets(S);
- n = strlen(S);
- sam = SuffixAutomation(n);
- }
- void getDag() {
- for(TrieNode* p = sam.pool; p != sam.top; p++) {
- for(int i = ; i < CharSet; i++)
- if(p->next[i])
- p->next[i]->dag++;
- }
- }
- queue<TrieNode*> que;
- void bfs() {
- sam.root->cnt = ;
- que.push(sam.root);
- while(!que.empty()) {
- TrieNode* e = que.front();
- que.pop();
- if(e->next[]) {
- e->next[]->dag--, e->next[]->cnta += e->cnt, e->next[]->cnt += e->cnt;
- if(!e->next[]->dag)
- que.push(e->next[]);
- }
- for(int i = ; i < CharSet; i++) {
- TrieNode* eu = e->next[i];
- if(eu) {
- eu->dag--;
- if(!eu->dag)
- que.push(eu);
- eu->cnt += e->cnt;
- eu->cnta += e->cnta;
- }
- }
- }
- }
- long long res = ;
- inline void solve() {
- for(int i = ; i < n; i++)
- sam.extends(S[i]);
- getDag();
- bfs();
- for(TrieNode* p = sam.pool; p != sam.top; p++) {
- res += p->cnta;
- }
- printf(Auto, res);
- }
- int main() {
- freopen("substring.in", "r", stdin);
- freopen("substring.out", "w", stdout);
- init();
- solve();
- return ;
- }
String & dp Problem Round 3 2017.4.22的更多相关文章
- 2017/11/22 Leetcode 日记
2017/11/22 Leetcode 日记 136. Single Number Given an array of integers, every element appears twice ex ...
- 【CF954I】Yet Another String Matching Problem(FFT)
[CF954I]Yet Another String Matching Problem(FFT) 题面 给定两个字符串\(S,T\) 求\(S\)所有长度为\(|T|\)的子串与\(T\)的距离 两个 ...
- Kickstart Round D 2017 problem A sightseeing 一道DP
这是现场完整做出来的唯一一道题Orz..而且还调了很久的bug.还是太弱了. Problem When you travel, you like to spend time sightseeing i ...
- Educational Codeforces Round 16 E. Generate a String dp
题目链接: http://codeforces.com/problemset/problem/710/E E. Generate a String time limit per test 2 seco ...
- Codeforces Round #282 Div.1 B Obsessive String --DP
题意: 给两个串S,T,问能找出多少的S的(a1,b1)(a2,b2)..(ak,bk),使Sa1---Sb1,...Sak---Sbk都包含子串T,其中k>=1,且(a1,b1)...(ak, ...
- Educational Codeforces Round 40 I. Yet Another String Matching Problem
http://codeforces.com/contest/954/problem/I 给你两个串s,p,求上一个串的长度为|p|的所有子串和p的差距是多少,两个串的差距就是每次把一个字符变成另一个字 ...
- codeforces 710E E. Generate a String(dp)
题目链接: E. Generate a String time limit per test 2 seconds memory limit per test 512 megabytes input s ...
- hdu5362 Just A String(dp)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Just A String Time Limit: 2000/1000 MS (J ...
- Codeforces 954I Yet Another String Matching Problem(并查集 + FFT)
题目链接 Educational Codeforces Round 40 Problem I 题意 定义两个长度相等的字符串之间的距离为: 把两个字符串中所有同一种字符变成另外一种,使得两个 ...
随机推荐
- centos 7 yum configuration; yum localinstall
Linux下对于软件包的管理使用rpm管理方式.直接使用rpm包管理工具来进行rpm包的安装,升级,卸载时,对于最让人头疼的莫过与包之间的依赖关系.yum作为一个rpm包前端管理工具,可以自动处理依赖 ...
- version `GLIBC_2.14' not found问题
先对比下源码编译.RPM 包和 YUM 三种安装方法的优劣: 源码编译:可以自行指定编译参数,自由度高,略显麻烦.但是如果不安装最新版本,BUGs 和 CVEs 是不会被修复的,和咸鱼没什么差别: R ...
- IDEA 配置环境和相关工具整理(新手入门)
转载自:https://blog.csdn.net/moneyshi/article/details/79722360 因项目环境需要,开发工具需要统一 , 项目团队都使用idea,所以不得已自己也配 ...
- AWTK 全称为 Toolkit AnyWhere,是 ZLG 倾心打造的一套基于 C 语言开发的 GUI 框架(三平台+2个手机平台+嵌入式)
最终目标: 支持开发嵌入式软件. 支持开发Linux应用程序. 支持开发MacOS应用程序. 支持开发Windows应用程序. 支持开发Android应用程序. 支持开发iOS应用程序. 支持开发2D ...
- 优云软件助阵ArchSummit全球架构师峰会
由极客邦科技与 InfoQ 中国主办的 ArchSummit 全球架构师峰会深圳站,于 7 月 7 日 - 8 日在深圳华侨城洲际酒店举办. 本次大会特邀 100 多位国内外技术专家,与1000余名技 ...
- webview与js交互(转)
原文:http://www.cnblogs.com/vanezkw/archive/2012/07/02/2572799.html 对于android初学者应该都了解webView这个组件.之前我也是 ...
- java进程和线程的区别
什么是进程,什么是线程系统要做一件事,运行一个任务,所有运行的任务通常就是一个程序:每个运行中的程序就是一个进程,这一点在任务管理器上面可以形象的看到.当一个程序运行时,内部可能会包含多个顺序执行流, ...
- (3.10)mysql基础深入——mysqld 服务器与客户端连接过程 源码分析【待写】
(3.10)mysql基础深入——mysqld 服务器与客户端连接过程 源码分析[待写]
- Spark Shuffle Write阶段磁盘文件分析
这篇文章会详细介绍,Sort Based Shuffle Write 阶段是如何进行落磁盘的 流程分析 入口处: org.apache.spark.scheduler.ShuffleMapTask.r ...
- PHP操作Redis常用技巧
这篇文章主要介绍了PHP操作Redis常用技巧,结合实例形式总结分析了php针对redis的连接.认证.string.hash等操作技巧与注意事项,需要的朋友可以参考下 本文实例讲述了PHP操作Red ...