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

  需要解决这个两个问题

  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的更多相关文章

  1. 2017/11/22 Leetcode 日记

    2017/11/22 Leetcode 日记 136. Single Number Given an array of integers, every element appears twice ex ...

  2. 【CF954I】Yet Another String Matching Problem(FFT)

    [CF954I]Yet Another String Matching Problem(FFT) 题面 给定两个字符串\(S,T\) 求\(S\)所有长度为\(|T|\)的子串与\(T\)的距离 两个 ...

  3. Kickstart Round D 2017 problem A sightseeing 一道DP

    这是现场完整做出来的唯一一道题Orz..而且还调了很久的bug.还是太弱了. Problem When you travel, you like to spend time sightseeing i ...

  4. 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 ...

  5. 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, ...

  6. Educational Codeforces Round 40 I. Yet Another String Matching Problem

    http://codeforces.com/contest/954/problem/I 给你两个串s,p,求上一个串的长度为|p|的所有子串和p的差距是多少,两个串的差距就是每次把一个字符变成另一个字 ...

  7. 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 ...

  8. hdu5362 Just A String(dp)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Just A String Time Limit: 2000/1000 MS (J ...

  9. Codeforces 954I Yet Another String Matching Problem(并查集 + FFT)

    题目链接  Educational Codeforces Round 40  Problem I 题意  定义两个长度相等的字符串之间的距离为:   把两个字符串中所有同一种字符变成另外一种,使得两个 ...

随机推荐

  1. CCCC 月饼

    https://www.patest.cn/contests/gplt/L2-003 题解:按平均值贪心. 坑:有一个样例卡住了,是因为 while (i<=n&&x - bs[ ...

  2. HDU - 5818 Joint Stacks 比较大の模拟,stack,erase

    https://vjudge.net/problem/HDU-5818 题意:给你两个栈AB,有常规push,pop操作,以及一个merge操作,merge A B 即将A.B的元素按照入栈顺序全部出 ...

  3. ubuntu环境下快速搭建开发环境

    接触ubuntu已经半年了,虽然游戏啊qq啊在linux下配置稍微麻烦一些,但是作为开发环境,ubuntu真的是好东西,无论是c啊还是php and etc 看到官网上文档开发环境建议wamp,如果是 ...

  4. Java-idea-eclipse-快捷键【mac,win】

    Mac键盘符号和修饰键说明 ⌘ Command ⇧ Shift ⌥ Option ⌃ Control ↩︎ Return/Enter ⌫ Delete ⌦ 向前删除键(Fn+Delete) ↑ 上箭头 ...

  5. RGB颜色参考

    实色效果 英文名称 R.G.B 16色 实色效果 英文名称 R.G.B 16色   Snow 255 250 250 #FFFAFA   PaleTurquoise1 187 255 255 #BBF ...

  6. 循环结构 while,do while

    while:先判断条件表达式是否成立,成立则执行循环体,不成立则不执行. 格式:while(条件表达式){ 执行语句(控制循环次数): } 例如: int x=1; while(x<3/*条件表 ...

  7. 主成分分析(PCA)算法,K-L变换 角度

    主成分分析(PCA)是多元统计分析中用来分析数据的一种方法,它是用一种较少数 量的特征对样本进行描述以达到降低特征空间维数的方法,它的本质实际上是K-L变换.PCA方法最著名的应用应该是在人脸识别中特 ...

  8. soapUI-Groovy Script

    1.1.1  Groovy Script soapUI通过以groovy语言编写的脚本来大量支持您的项目. Groovy脚本TestSteps可用于向功能TestCase添加任意功能. 脚本断言用于任 ...

  9. 9/252D图的画法

    我们在介绍之前先想想2D图的一些元素 我在这里按我的思路写下一些: 坐标轴(尺度,区间..),线条(样式,颜色...),图和线的标签和注释,图像大小,图像里图片的排版(一张图像中多张图) 下面我们将分 ...

  10. Vue.Js添加自定义插件

    基于上篇我们讲了 在window下搭建Vue.Js开发环境 我们可以开发自己的vue.js插件发布到npm上,供大家下载使用. 1.首先打开cmd命令窗口,进入我们的工作目录下 执行 cd E:\vu ...