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 题意 定义两个长度相等的字符串之间的距离为: 把两个字符串中所有同一种字符变成另外一种,使得两个 ...
随机推荐
- Balanced Lineup---poj3264线段树基础
题目链接 求对应区间最大值与最小值的差: #include<stdio.h> #include<string.h> #include<algorithm> #inc ...
- CentOS VmwareTools安装
1. 虚拟机菜单栏--虚拟机--安装VMware tools 2. CentOS系统中弹出的VMware tools窗口中--右击VMwaretools.tar.gz--Extract到桌面 3.打开 ...
- util date 转 sql date
JAVA 处理时间 - java.sql.Date.java.util.Date与数据库中的Date字段的转换方法,以及util包下的Date类与字符串的相互转换在java环境中使用的Date时间类通 ...
- java NIO (二) 一个故事讲清楚NIO
假设某银行只有10个职员.该银行的业务流程分为以下4个步骤: 1) 顾客填申请表(5分钟): 2) 职员审核(1分钟): 3) 职员叫保安去金库取钱(3分钟): 4) 职员打印票据,并将钱和票据返回给 ...
- HTML5插件
HTML 助手(插件) 辅助应用程序(helper application)是可由浏览器启动的程序.辅助应用程序也称为插件. 辅助程序可用于播放音频和视频(以及其他).辅助程序是使用 <obje ...
- mathType插入公式编号,及对公式编号的字体进行修改。调整公式上下间距。
一:插入 公式编号. 1:首先设置公式格式.点击 mathtype>insert number >format 2:有简单格式和 高级格式: https://we ...
- [py]django上线部署-uwsgi+nginx+py3/django1.10
https://github.com/lannyMa/django-uwsgi-nginx.git 单机调试启动-确保项目代码没问题 - 克隆代码进入项目 git clone https://gith ...
- Vim/Vi的使用
Vim 是vi的加强 Gvim图形化的vim Vim/Vi简介 Vim/Vi是一个功能强大的全屏幕文本编辑器,是Linux/Unix上最常用的文本编辑器,他们 的作用是建立,编辑,显示文本文件 Vi ...
- linux命令:linux文件处理命令
命令格式 : 命令 [-选项] [参数] 例:ls -la /etc 说明:1)个别命令使用不遵循此格式,[]代表可选 2)当有多个选项时,可以写在一起 3)-a等于 --all,调用简化选项用 ...
- #C++初学记录(ACM试题1)
A - Diverse Strings A string is called diverse if it contains consecutive (adjacent) letters of the ...