-
Notifications
You must be signed in to change notification settings - Fork 0
String
hotman edited this page Oct 25, 2020
·
3 revisions
#pragma once
#include<string>
#include<queue>
/**
* @brief Aho-Corasick法
*/
class AhoCorasick{
struct node;
using np=node*;
constexpr static int num=26;
constexpr static char base='A';
struct node{
np ch[num];
np link=nullptr;
int val=0;
node(){
for(int i=0;i<num;++i)ch[i]=nullptr;
}
};
np root=new node();
np root_par=new node();
public:
AhoCorasick(){
root->link=root_par;
for(int i=0;i<num;++i)root_par->ch[i]=root;
}
void insert(std::string v){
np t=root;
int idx=0;
while(idx<(int)v.size()){
if(!t->ch[v[idx]-base])t->ch[v[idx]-base]=new node();
t=t->ch[v[idx]-base];
idx++;
}
t->val++;
}
void build(){
built=1;
std::queue<np>que;
que.push(root);
while(!que.empty()){
np t=que.front();
que.pop();
for(int i=0;i<num;++i){
if(!t->ch[i])continue;
if(t==root){
t->ch[i]->link=t;
}else{
np s=t->link;
while(!s->ch[i]){
s=s->link;
}
t->ch[i]->link=s->ch[i];
}
que.push(t->ch[i]);
}
}
}
bool built=0;
int count(std::string v){
if(!built){build();built=1;}
np t=root;
int idx=0;
int res=0;
while(idx<(int)v.size()){
while(!t->ch[v[idx]-base]){
if(t==root){
idx++;
if(idx==(int)v.size())return res;
}else{
t=t->link;
}
}
t=t->ch[v[idx++]-base];
auto s=t;
while(s!=root){
res+=s->val;
s=s->link;
}
}
return res;
}
int find_first(std::string v){
if(!built){build();built=1;}
np t=root;
int idx=0;
int res=0;
while(idx<(int)v.size()){
while(!t->ch[v[idx]-base]){
if(t==root){
res++;
idx++;
if(idx==(int)v.size())return -1;
}else{
res++;
t=t->link;
}
}
t=t->ch[v[idx++]-base];
if(t->val>0)return res;
}
return -1;
}
};
#pragma once
#include<string>
#include<vector>
/**
* @brief Manacher
*/
std::vector<int> manacher(std::string S){
int i = 0, j = 0;
std::string s;
for(int i=0;i<(int)S.size();i++){
if(i)s+='$';
s+=S[i];
}
int n=s.size();
std::vector<int>res(n,0);
while (i<n) {
while(i-j>=0&&i+j<n&&s[i-j]==s[i+j])++j;
res[i]=j;
int k=1;
while (i-k >= 0 && k+res[i-k]<j)res[i+k]=res[i-k],++k;
i+=k;j-=k;
}
for(int i=0;i<n;++i){
if(i%2)res[i]=res[i]/2;
else res[i]=(res[i]+1)/2;
}
return res;
}
#pragma once
#include<string>
#include<vector>
#include<set>
/**
* @brief オンラインZアルゴリズム
*/
struct online_Zalgo{
std::vector<int>z;
std::set<int>memo;
std::vector<std::vector<int>>hist;
std::string s="";
int sz=0;
void add(char c){
s+=c;
memo.emplace(sz);
z.push_back(-1);
hist.push_back(std::vector<int>());
sz++;
int mx=-1;
for(auto itr=next(memo.begin(),1);itr!=memo.end();){
auto idx=*itr;
if(s[sz-idx-1]!=s.back()){
itr=memo.erase(itr);
z[idx]=sz-idx-1;
hist.back().push_back(idx);
}else{
mx=idx;
break;
}
}
if(mx==-1)return;
for(auto e:hist[sz-1-mx]){
memo.erase(mx+e);
z[mx+e]=sz-(mx+e)-1;
hist.back().push_back(mx+e);
}
}
int operator[](int idx){
if(memo.count(idx))return sz-idx;
else return z[idx];
}
};
#pragma once
#include<string>
#include<vector>
#include<set>
#include<tuple>
/**
* @brief ローリングハッシュ
*/
struct rolling_hash{
using u64=std::uint64_t;
constexpr static u64 mod=(1ULL<<61)-1;
constexpr static u64 base=10007;
int sz;
u64 hash;
constexpr rolling_hash():sz(0),hash(0){}
constexpr rolling_hash(char c):sz(1),hash(c){}
rolling_hash(std::string s):sz(0),hash(0){
for(auto c:s)(*this)+=c;
}
constexpr u64 pow(u64 s,int t){
u64 ret=1;
while(t){
if(t&1)ret=mul(ret,s);
s=mul(s,s);
t/=2;
}
return ret;
}
constexpr u64 add(u64 s,u64 t)noexcept{
s+=t;
return s>=mod?s-mod:s;
}
constexpr u64 sub(u64 s,u64 t)noexcept{
if(s<t)s+=mod;
return s-t;
}
constexpr u64 mul(u64 a,u64 b)noexcept{
u64 au=a>>31,ad=a&((1ULL<<31)-1);
u64 bu=b>>31,bd=b&((1ULL<<31)-1);
u64 mid=au*bd+ad*bu;
u64 ret=(au*bu*2+ad*bd+(mid>>30)+((mid&((1ULL<<30)-1))<<31));
ret=(ret>>61)+(ret&mod);
return ret>=mod?ret-mod:ret;
}
constexpr rolling_hash operator+(rolling_hash s)const noexcept{return rolling_hash(*this)+=s;}
constexpr bool operator==(rolling_hash s)noexcept{return hash==s.hash&&sz==s.sz;}
constexpr bool operator<(rolling_hash s)const noexcept{return std::make_pair(hash,sz)<std::make_pair(s.hash,s.sz);}
constexpr bool operator>(rolling_hash s)const noexcept{return std::make_pair(hash,sz)>std::make_pair(s.hash,s.sz);}
constexpr bool operator<=(rolling_hash s)const noexcept{return std::make_pair(hash,sz)<=std::make_pair(s.hash,s.sz);}
constexpr bool operator>=(rolling_hash s)const noexcept{return std::make_pair(hash,sz)>=std::make_pair(s.hash,s.sz);}
constexpr rolling_hash operator+=(rolling_hash s)noexcept{
(*this).hash=add((*this).hash*pow(base,s.sz),s.hash);
(*this).sz+=s.sz;
return *this;
}
constexpr int size(){return sz;}
};
#pragma once
#include<string>
#include<vector>
#include<set>
#include<tuple>
/**
* @brief 部分列DP(WIP)
*/
struct subsequence{
struct node;
using np=node*;
struct node{
np ch[26]={};
int idx;
char c;
node(int idx,char c):idx(idx),c(c){}
};
std::string s;int n;
std::vector<std::vector<int>>m;
std::vector<np>v;
np root=0;
subsequence(std::string s):s(s),n(s.size()),m(n+1,std::vector<int>(26,-1)),v(n+1){
for(int i=n-1;i>=0;--i){
m[i]=m[i+1];
m[i][s[i]-'a']=i;
}
for(int i=0;i<n+1;++i)v[i]=new node(i,(i?s[i-1]:'#'));
for(int i=0;i<n;++i){
for(int j=0;j<26;++j){
if(~m[i][j])v[i]->ch[j]=v[m[i][j]+1];
}
}
root=v[0];
}
//ここから問題ごとに書く
std::vector<long long>dp;
void dp2(){
dp.resize(n+1);
for(int i=n;i>=0;--i){
np t=v[i];
dp[i]=;
for(int j=0;j<26;++j){
if(!t->ch[j])dp[i]=1;
else dp[i]=min(dp[i],dp[t->ch[j]->idx]+1);
}
}
}
string ans;
void dfs(np t){
for(int i=0;i<26;i++){
if(!t->ch[i]){
if(t!=root)ans+=t->c;
ans+=char(i+'a');
return;
}
if(dp[t->ch[i]->idx]==dp[t->idx]-1){
if(t!=root)ans+=t->c;
dfs(t->ch[i]);
return;
}
}
}
string solve(){
dp2();
dfs(root);
return ans;
}
};
#pragma once
#include<string>
#include<vector>
#include<algorithm>
#include <numeric>
#include<cmath>
/**
* @brief SuffixArray
*/
std::vector<int> suffix_array(std::string s){
int n=s.size();
std::vector<int> v1(n,-1),v2(n,-1);
std::vector<int> rank(n,-1);
std::iota(v1.begin(),v1.end(),0);
std::iota(v2.begin(),v2.end(),0);
std::sort(v1.begin(),v1.end(),[&](auto p,auto q){return s[p]<s[q];});
int idx=0;
for(int i=0;i<n;++i){
rank[v1[i]]=idx;
if(i<n-1&&s[v1[i]]!=s[v1[i+1]])idx++;
}
for(int i=0;i<(int)std::log2(n)+2;++i){
const int h=1<<i;
std::sort(v2.begin(),v2.end(),[&](auto p,auto q){
return make_pair(rank[p],p+h<n?rank[p+h]:-1)<make_pair(rank[q],q+h<n?rank[q+h]:-1);
});
swap(v1,v2);
idx=0;
std::vector<int> tmp(n,-1);
for(int j=0;j<n;++j){
tmp[v1[j]]=idx;
if(j<n-1&&std::make_pair(rank[v1[j]],v1[j]+h<n?rank[v1[j]+h]:-1)<std::make_pair(rank[v1[j+1]],v1[j+1]+h<n?rank[v1[j+1]+h]:-1))idx++;
}
std::swap(rank,tmp);
}
return v1;
}
#pragma once
#include<string>
#include<vector>
#include<algorithm>
/**
* @brief Zアルゴリズム
*/
std::vector<int> Z_algorizm(const std::string& s){
std::vector<int>res(s.size());
res[0]=s.size();
int i=1,j=0;
while(i<(int)s.size()){
while(i+j<(int)s.size()&&s[j]==s[i+j])++j;
res[i]=j;
if(j==0){++i;continue;}
int k=1;
while(i+k<(int)s.size()&&k+res[k]<j)res[i+k]=res[k],++k;
i+=k;j-=k;
}
return res;
}
int find_first(const std::string& s,const std::string& t){
auto d=Z_algorizm(s+"#"+t);
auto itr=std::find(d.begin()+s.size(),d.end(),s.size());
if(itr!=d.end())return itr-d.begin()-s.size();
else return -1;
}
int count(const std::string& s,const std::string& t){
auto d=Z_algorizm(s+"#"+t);
return std::count(d.begin()+s.size(),d.end(),s.size());
}