板子

板子汇总

字符串

后缀自动机

P3804 【模板】后缀自动机(SAM)

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e6;
struct Suffix_Automaton{
    /**********    beg    **********/
    int len[maxn<<1];
    int ch[maxn<<1][26];
    int link[maxn<<1];
    int siz,last;
    
    void init(){
        len[0]=0;
        for(int i=0;i<26;i++)ch[0][i]=0;
        link[0]=-1;
        siz=last=0;
    }
    void extend(int c){
        int cur=++siz,p=last;
        len[cur]=len[p]+1;
        for(int i=0;i<26;i++)ch[cur][i]=0;
        for(;p!=-1&&!ch[p][c];p=link[p])ch[p][c]=cur;
        if(p==-1)link[cur]=0;
        else{
            int q=ch[p][c];
            if(len[p]+1==len[q])link[cur]=q;
            else{
                int copy=++siz;
                len[copy]=len[p]+1;
                for(int i=0;i<26;i++)ch[copy][i]=ch[q][i];
                for(;p!=-1&&ch[p][c]==q;p=link[p])ch[p][c]=copy;
                link[copy]=link[q];
                link[cur]=link[q]=copy;
            }
        }
        last=cur;
    }
    void print(){//打印错误
        cout<<"len"<<endl;
        for(int i=0;i<=siz;i++)cout<<len[i]<<" \n"[i==siz];
        
        cout<<"ch"<<endl;
        for(int i=0;i<=siz;i++){
            for(int j=0;j<26;j++){
                if(ch[i][j])cout<<i<<" - "<<(char)('a'+j)<<" - "<<ch[i][j]<<endl;
            }
        }
        
        cout<<"link"<<endl;
        for(int i=0;i<=siz;i++)cout<<link[i]<<" \n"[i==siz];
    }
    /**********    end    **********/
    
    int cnt[maxn<<1];//状态出现次数
    vector<int> id[maxn];//长度为i的状态编号
    void solve(){
        //cin
        string s;cin>>s;
        
        //构造sam
        init();
        for(int i=0;i<s.size();i++)extend(s[i]-'a');
        
        //将状态按长度分类
        //性质1:s长度为i的前缀状态恰好为id[i][0]
        //性质2:按长度跑 状态转移ch,后缀链接link 恰好符合一种拓扑序
        for(int i=0;i<=siz;i++)id[len[i]].push_back(i);//len_id
        
        //出现次数 按反向拓扑序跑
        int LENMAX=s.size();//字符串长度
        for(int i=LENMAX;i>=1;i--){//cnt
            cnt[id[i][0]]++;//终止状态次数出现次数加一
            for(auto x:id[i]){
                cnt[link[x]]+=cnt[x];
            }
        }
        
        //计算结果
        long long ans=0;
        for(int i=0;i<=siz;i++)if(cnt[i]>1)ans=max(ans,1ll*cnt[i]*len[i]);
        cout<<ans<<endl;
    }
}sam;

int main(){
    sam.solve();
}

多项式

多项式乘法(FFT)

P3803 【模板】多项式乘法(FFT)

/*
[模板] 多项式乘法(FFT):
给定一个 n 次多项式 F(x),和一个 m 次多项式 G(x)。
请求出 F(x) 和 G(x) 的卷积。

复杂度 nlogn
*/

#include<bits/stdc++.h>
using namespace std;
typedef complex<double> cd;
int read(){
	int x=0,f=1;char ch=getchar();
    while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}
    return x;
}
void wr(int a){
	if(a<0)putchar('-'),a=-a;
    if(a<=9)putchar(a|'0');
    else{wr(a/10),putchar((a%10)|'0');}
}

void fft(vector<cd> &a,bool invert){
    int n=a.size();
    if(n==1)return;
    
    vector<cd> a0(n/2),a1(n/2);
    for(int i=0,j=0;i<n;i+=2,++j)a0[j]=a[i],a1[j]=a[i+1];
    fft(a0,invert);
    fft(a1,invert);
    
    double ang=2*M_PI/n*(invert?-1:1);
    cd w(1),wn(cos(ang),sin(ang));
    for(int i=0;i<n/2;++i){
        a[i]=a0[i]+w*a1[i];
        a[i+n/2]=a0[i]-w*a1[i];
        if(invert)a[i]/=2,a[i+n/2]/=2;
        w*=wn;
    }
}

vector<int> multiply(vector<int> &a,vector<int> &b){
    vector<cd> fa(a.begin(),a.end()),fb(b.begin(),b.end());
    int n=1;while(n<max(a.size(),b.size()))n<<=1;n<<=1;
    fa.resize(n),fb.resize(n);
    
    fft(fa,false),fft(fb,false);
    for(int i=0;i<n;i++)fa[i]*=fb[i];
    fft(fa,true);
    
    vector<int> res(n);
    for(int i=0;i<n;++i)res[i]=round(fa[i].real());
    return res;
}

signed main(){
    int n=read(),m=read();
    vector<int> a(n+1);
    vector<int> b(m+1);
    for(int i=0;i<=n;i++)a[i]=read();
    for(int i=0;i<=m;i++)b[i]=read();
    
    vector<int> c=multiply(a,b);
    for(int i=0;i<=n+m;i++)wr(c[i]),putchar(' ');
	
    return 0;
}

posted @ 2024-08-02 10:46  菜狗非狗  阅读(49)  评论(0)    收藏  举报