板子-GOD BLESS ALL OF YOU

字符串:

KMP

#include<cstdio>
#include<cstring>

const int N=1000004;

char s1[N],s2[N/100];
int next[N/100];

int l1,l2;

void get_next()
{
    next[0]=-1;
    for(int i=2,j=0;i<=l2;++i)
    {
        for(;s2[i]!=s2[j+1]&&j>0;j=next[j]);
        if(s2[i]==s2[j+1])next[i]=++j;
    }
}

void kmp()
{
    for(int i=1,j=0;i<=l1;i++)
    {
        for(;s1[i]!=s2[j+1]&&j>0;j=next[j]);
        if(s1[i]==s2[j+1])++j;
        if(j==l2)
            printf("%d
",i-l2+1),j=next[l2];
    }
}
int main()
{
    scanf("%s%s",s1+1,s2+1);
    l1=strlen(s1+1);
    l2=strlen(s2+1);
    get_next();
    kmp();
    for(int i=1;i<=l2;i++)
    {
        printf("%d ",next[i]);
    }
    return 0;
}
kmp

AC自动机last指针版

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int  maxn = 100001;
int n;
char s[maxn][101];
char ss[maxn*10];
int ans=0;
struct Aho_Corasick_automato {
    int sz;
    int ch[maxn][26];
    int cnt[maxn];
    int val[maxn];
    int last[maxn];
    int fail[maxn];
    int num;
    void init() {
        memset(ch[0],0,sizeof(ch[0]));
        memset(cnt,0,sizeof(cnt));
        sz=1;
    }
    void insert(char *s,int num) {
        int len=strlen(s);
        int u=0;
        for(int i=0; i<len; ++i) {
            int v=(s[i]-'a');
            if(!ch[u][v]) {
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][v]=sz++;
            }
            u=ch[u][v];
        }
        val[u]=num;
    }
    void get_fail() {
        fail[0]=0;
        queue<int>que;
        for(int i=0; i<26; i++) {
            int u=ch[0][i];
            if(u) {
                fail[u]=0;
                que.push(u);
            }
        }
        while(!que.empty()) {
            int u=que.front();
            que.pop();
            for(int i=0; i<26; i++) {
                int v=ch[u][i];
                if(!v) {
                    ch[u][i]=ch[fail[u]][i];
                    continue;
                }
                que.push(v);
                int k=fail[u];
                fail[v]=ch[k][i];
                last[v]=val[fail[v]] ? fail[v] : last[fail[v]];
            }
        }
    }
    void work(int x) {
        if(x) {
            cnt[val[x]]++;
            work(last[x]);
        }
    }
    void find(char *s) {
        int len=strlen(s);
        int u=0;
        for(int i=0; i<len; i++) {
            int v=(s[i]-'a');
            if(!ch[u][v])u=fail[u];
            while(u&&!ch[u][v])
                u=fail[u];
            u=ch[u][v];
            if(val[u])
                work(u);
            else if(last[u])
                work(last[u]);
        }
    }
} ac;

int main() {


    while(scanf("%d",&n)==1&&n!=0) {
        ac.init();
        for(int i=1; i<=n; i++) {
            scanf("%s",s[i]);
            ac.insert(s[i],i);
        }
        ac.get_fail();
        scanf("%s",ss);
        ac.find(ss);
        int ans=0,r;
        for(int i=1;i<=n;i++)
            if(ac.cnt[i]>ans)ans=ac.cnt[i],r=i;;
        printf("%d
",ans);
         for(int r=1;r<=n;r++)
            if(ac.cnt[r]==ans)
                printf("%s
",s[r]);
        }
    return 0;
}
AC自动机

马拉车

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 33000000

int n,p[N],ans;
char s[N],str[N];
void manachar() 
{
    int mx=0,id;
    for(int i=n; str[i]!=0; i++)str[i]=0;
    for(int i=1; i<n; i++) 
    {
        if(mx>i)
            p[i]=min(p[2*id-i],p[id]+id-i);
        else 
            p[i]=1;
        for(;str[i+p[i]]==str[i-p[i]];++p[i]);
        if(p[i]+i>mx) 
            mx=p[i]+i,
            id=i;
    }
}
void csh()
{
    str[0]='#';
    str[1]='#';
    for(int i=0;i<n;i++)
    str[(i<<1)+2]=s[i],str[(i<<1)+3]='#';
    n=(n<<1)+2;
    str[n]=0;
}
int main() {
    scanf("%s",s);
    n=strlen(s);
    csh();
    manachar();
    ans=0;
    for(int i=0;i<n;i++)
        ans=max(ans,p[i]);
    printf("%d
",ans-1);
    return 0;
}
manacher

 字符串hash

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef unsigned long long ull;
ull base = 131;
char s[100000];
ull a[100000];
ull hashs(char *s)
{
    int len=strlen(s);
    ull ans=0;
    for(int i=0;i<len;i++)
        ans=ans*base+(ull)s[i];
    return ans&0x7fffffff;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%s",s);
        a[i]=hashs(s);
    }
    sort(a+1,a+n+1);
    int ans=0;
    for(int i=2;i<=n;i++)
         if(a[i]!=a[i-1]) ans++;
    printf("%d
",++ans);
    return 0;
}
字符串hash

 后缀数组

#include<cstdio>
#include<cstring>
#include<algorithm>
using std::swap;
const int maxn=2000010;

char c[maxn];
int s[maxn],sa[maxn];//后缀排名的位置
int rank[maxn];//后缀排名
int height[maxn];//常规操作
int saf[maxn];//用saf[]作为第2关键字后缀的第一关键字
int cs[maxn];//基数排序中的排名计数器
int n,m;
void rsort() {//第二关键字基数排序
    for(int i=0;i<=m;++i)cs[i]=0;
    for(int i=1;i<=n;++i)cs[rank[saf[i]]]++;
    for(int i=1;i<=m;++i)cs[i]+=cs[i-1];
    for(int i=n;i>=1;--i)sa[cs[rank[saf[i]]]--]=saf[i];//利用第二关键字排名更新sa
}
int cmp(int *f,int x,int y,int w) {
    return f[x]==f[y]&&f[x+w]==f[y+w];//cmp 
}
void get_sa() {
    for(int i=1;i<=n;++i)rank[i]=s[i],saf[i]=i;//此时saf[i]指向自己作为第一关键字的后缀
    m=127;rsort();
    for(int p=1,w=1,i;p<n;w<<=1,m=p) {//w为倍增长度,<选取第几位作为第二关键字>
        for(i=n-w+1,p=0;i<=n;++i)saf[++p]=i;
        for(i=1;i<=n;++i)if(sa[i]>w)saf[++p]=sa[i]-w;//利用上次的sa[]值更新下一次的saf[],有的字母已经不能再作为后缀的第n位的关键字了0
        rsort();swap(rank,saf);rank[sa[1]]=p=1;//p用来记录已经不需要再比较'第三关键字的'的后缀//当p=n是说明排序完成
        for(i=2;i<=n;++i)rank[sa[i]]=cmp(saf,sa[i],sa[i-1],w)?p:++p;//比较第一关键词与自己排名相临的,若第二关键字相同则需继续比较
    }
    //int j,k=0;
    //for(int i=1;i<=n;height[rank[i++]]=k)
      //  for(k=k?k-1:k,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
}
int main() {
    scanf("%s",c+1);
    n=strlen(c+1);
    for(int i=1;i<=n;++i)s[i]=c[i];
    s[0]=s[n+1]=-1;
    get_sa();
    for(int i=1;i<=n;++i) {
        printf("%d ",sa[i]);
    }
    return 0;
}
后缀数组

数据结构

手写heap

void put(int r) 
{
    while(r>1&&a[r]<a[r/2]) 
    {
        h=a[r];
        a[r]=a[r/2];
        a[r/2]=h;
        r/=2;
    }
}
int flag=1;
int get()//弹出最小值 
{
    if(flag==1)
    {
        sum=a[1];
        flag=0;
    }
    else sum+=a[1];
    a[1]=a[len];
    len--;
    r=1;
    while((r*2<=len&&a[r]>a[r*2])||(r*2+1<=len&&a[r]>a[r*2+1]))
        {
            j=r*2;
            if(j+1<=len&&a[j]>a[j+1])j++;
            h=a[r];
            a[r]=a[j];
            a[j]=h;
            r=j;
        }
}
heap

树状数组

1单点修改+区间查询

//树状数组:区间查询,单点修改 
#include<cstdio>
int sum[500100];
int n,m;
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int v)
{
    while (x<=n)
    {
        sum[x] += v;
        x += lowbit(x);
    }
}
int query(int x)
{
    int ans = 0;
    while (x)
    {
        ans += sum[x];
        x -= lowbit(x);
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int a,i=1; i<=n; ++i)
    {
        scanf("%d",&a);
        update(i,a);
    }
    for (int i=1; i<=m; ++i)
    {
        int x,y,z;
        scanf("%d%d%d",&z,&x,&y);
        if (z==1) update(x,y);    //单点修改 
        else printf("%d
",query(y)-query(x-1));
    }
    return 0;
}
树状数组1

2区间修改+单点查询

//树状数组:区间修改,单点查询,差分 
#include<cstdio>
int sum[500100];
int n,m,last = 0;
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int v)
{
    while (x<=n)
    {
        sum[x] += v;
        x += lowbit(x);
    }
}
int query(int x)
{
    int ans = 0;
    while (x)
    {
        ans += sum[x];
        x -= lowbit(x);
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int a,i=1; i<=n; ++i)
    {
        scanf("%d",&a);
        update(i,a-last);
        last = a;
    }
    for (int x,y,z,a,i=1; i<=m; ++i)
    {
        scanf("%d",&a);
        if (a==1)    //区间修改
        {
            scanf("%d%d%d",&x,&y,&z);
            update(x,z);
            update(y+1,-z); 
        } 
        else        //单点查询 
        {
            scanf("%d",&x);
            printf("%d
",query(x));
        }
    }
    return 0;
}
树状数组2

可持久化线段树(状态区间和)

#include<cstdio>
#include<iostream>
using namespace std;
#define N 100001
int n,m,cnt,ans;
int root[N*20];
int ls[N*20],sum[N*20],rs[N*20];
int ope[N];
void change(int l,int r,int &rt,int pre,int pos,int w)
{
    if(!rt)rt=++cnt;
    sum[rt]=sum[pre];
    if(l==r){sum[rt]=w;return;}
    int mid=(l+r)>>1;
    if(pos<=mid)rs[rt]=rs[pre],change(l,mid,ls[rt],ls[pre],pos,w);
    else ls[rt]=ls[pre],change(mid+1,r,rs[rt],rs[pre],pos,w);
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
void query(int l,int r,int rt,int opl,int opr)
{
    if(opl<=l&&opr>=r){
        ans+=sum[rt];return ;
    }
    int mid=(l+r)>>1;
    if(opl<=mid)query(l,mid,ls[rt],opl,opr);
    if(opr>mid)query(mid+1,r,rs[rt],opl,opr);
}

int main()
{
    scanf("%d%d",&n,&m);
    int x,y,z;
    for(int i=1;i<=n;i++)
    scanf("%d",&x),change(1,n,root[0],root[0],i,x);
    char s[3];
    int now=0;
    for(int i=1;i<=m;i++)
    {
        ope[i]=now;
        scanf("%s",s);
        if(s[0]=='M')
        {
            now++;
            ope[i]=now;
            scanf("%d%d",&x,&y);
            change(1,n,root[now],root[now-1],x,y);
        }
        else 
        {
            scanf("%d%d%d",&x,&y,&z);
            ans=0;
            query(1,n,root[ope[z]],x,y);
            printf("%d
",ans);
        }
    }
    return 0;
}
可持久化线段树

主席树k大值

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100001;
int ls[N*20],rs[N*20],sum[N*20];
int n,m,a[N],hash[N],cnt,root[N];
int x,y,k;
void lsh()
{
    sort(hash+1,hash+n+1);
    cnt=unique(hash+1,hash+n+1)-(hash+1);
    for(int i=1;i<=n;i++)a[i]=lower_bound(hash+1,hash+cnt+1,a[i])-hash;
}
int tot=0;
void build(int l,int r,int &rt,int pre,int w)
{
    rt=++tot;
    sum[rt]=sum[pre]+1;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(w<=mid)rs[rt]==rs[pre],build(l,mid,ls[rt],ls[pre],w);
    else ls[rt]=ls[pre],build(mid+1,r,rs[rt],rs[pre],w);
}
int query(int l,int r,int x,int y,int k)
{
    if(l==r)return l;
    int mid=l+r>>1,tmp=sum[ls[y]]-sum[ls[x]];
    if(tmp>=k)return query(l,mid,ls[x],ls[y],k);
    else return query(mid+1,r,rs[x],rs[y],k-tmp);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",a+i),hash[i]=a[i];
    lsh();
//    printf("%d
",cnt);for(int i=1;i<=cnt;i++) printf("%d ",hash[i]);
    for(int i=1;i<=n;i++) build(1,cnt,root[i],root[i-1],a[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&k);
        printf("%d
",hash[query(1,cnt,root[x-1],root[y],k)]);
    }
    return 0;
}
主席树

Splay tree 区间翻转区间标记

#include<cstdio>
#include<iostream>
using namespace std;
#define N 100005
int n,m;
struct node{
    int siz,fa,ch[2];//0zuo,1you;
    bool rev;
}tr[N];
int root;
void push_down(int rt)
{
    if(tr[rt].rev)
    {
        swap(tr[rt].ch[1],tr[rt].ch[0]);
        tr[rt].rev=0;
        tr[tr[rt].ch[0]].rev^=1;tr[tr[rt].ch[1]].rev^=1;
    }
}
void pushup(int rt)
{
    tr[rt].siz=tr[tr[rt].ch[0]].siz+tr[tr[rt].ch[1]].siz+1;
    return;
}
int find(int rt,int x)
{
    if(rt==0)return 0;
    push_down(rt);
    if(x<=tr[tr[rt].ch[0]].siz)return find(tr[rt].ch[0],x);
    if(x==tr[tr[rt].ch[0]].siz+1)return rt;
    return find(tr[rt].ch[1],x-tr[tr[rt].ch[0]].siz-1);
}
void rotate(int &rt,int x)
{
    int y=tr[x].fa,q=tr[y].fa;
    bool dy=tr[y].ch[1]==x,dz=tr[q].ch[1]==y;
    push_down(y);
    if(rt==y)rt=x,tr[x].fa=q;
    else tr[q].ch[dz]=x,tr[x].fa=q;
    tr[y].ch[dy]=tr[x].ch[dy^1],tr[tr[x].ch[dy^1]].fa=y;
    tr[x].ch[dy^1]=y,tr[y].fa=x;
    pushup(y);
    return ;
}
void splay(int &rt,int x)
{
    push_down(x);
    while(rt!=x)
    {
        int y=tr[x].fa;int q=tr[y].fa;
        if(y!=rt)
        {
            if(tr[y].ch[1]==x^tr[q].ch[1]==y)rotate(rt,x);
            else rotate(rt,y);
        }
        rotate(rt,x);
    }
    pushup(x);
    return;
}
void print(int rt)
{
    if(rt==0)return;
    push_down(rt);
    print(tr[rt].ch[0]);
    if(rt>1&&rt<n+2)printf("%d ",rt-1);
    print(tr[rt].ch[1]);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+2;i++)
    {
        tr[i].siz=n+3-i;tr[i].fa=i-1;tr[i].ch[1]=i+1;
    }
    tr[n+2].ch[1]=0,root=1;
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        splay(root,find(root,l));
        splay(tr[root].ch[1],find(root,r+2));
        tr[tr[tr[root].ch[1]].ch[0]].rev^=1;
    }
    print(root);
    return 0;
}
splay区间

Splay基本操作插入,删除,k大,值rank,前驱,后继

#include<cstdio>
#include<iostream>
using namespace std;
#define N 100005
int n,m;
struct node{
    int siz,fa,ch[2];//0zuo,1you;
    bool rev;
}tr[N];
int root;
void push_down(int rt)
{
    if(tr[rt].rev)
    {
        swap(tr[rt].ch[1],tr[rt].ch[0]);
        tr[rt].rev=0;
        tr[tr[rt].ch[0]].rev^=1;tr[tr[rt].ch[1]].rev^=1;
    }
}
void pushup(int rt)
{
    tr[rt].siz=tr[tr[rt].ch[0]].siz+tr[tr[rt].ch[1]].siz+1;
    return;
}
int find(int rt,int x)
{
    if(rt==0)return 0;
    push_down(rt);
    if(x<=tr[tr[rt].ch[0]].siz)return find(tr[rt].ch[0],x);
    if(x==tr[tr[rt].ch[0]].siz+1)return rt;
    return find(tr[rt].ch[1],x-tr[tr[rt].ch[0]].siz-1);
}
void rotate(int &rt,int x)
{
    int y=tr[x].fa,q=tr[y].fa;
    bool dy=tr[y].ch[1]==x,dz=tr[q].ch[1]==y;
    push_down(y);
    if(rt==y)rt=x,tr[x].fa=q;
    else tr[q].ch[dz]=x,tr[x].fa=q;
    tr[y].ch[dy]=tr[x].ch[dy^1],tr[tr[x].ch[dy^1]].fa=y;
    tr[x].ch[dy^1]=y,tr[y].fa=x;
    pushup(y);
    return ;
}
void splay(int &rt,int x)
{
    push_down(x);
    while(rt!=x)
    {
        int y=tr[x].fa;int q=tr[y].fa;
        if(y!=rt)
        {
            if(tr[y].ch[1]==x^tr[q].ch[1]==y)rotate(rt,x);
            else rotate(rt,y);
        }
        rotate(rt,x);
    }
    pushup(x);
    return;
}
void print(int rt)
{
    if(rt==0)return;
    push_down(rt);
    print(tr[rt].ch[0]);
    if(rt>1&&rt<n+2)printf("%d ",rt-1);
    print(tr[rt].ch[1]);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+2;i++)
    {
        tr[i].siz=n+3-i;tr[i].fa=i-1;tr[i].ch[1]=i+1;
    }
    tr[n+2].ch[1]=0,root=1;
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        splay(root,find(root,l));
        splay(tr[root].ch[1],find(root,r+2));
        tr[tr[tr[root].ch[1]].ch[0]].rev^=1;
    }
    print(root);
    return 0;
}
splay

treap

#include<cstdio>
#include<cstdlib>
#include<ctime>
#define N 500007
int inline read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int tree[N][2],val[N],key[N],siz[N],sz;
inline void update(int x) {
    siz[x]=1+siz[tree[x][0]]+siz[tree[x][1]];
}
int make_new(int v) {
    siz[++sz]=1;
    val[sz]=v;
    key[sz]=rand();
    return sz;
}
int merge(int x,int y) {
    if(!x) return y;
    else if(!y)return x;
    if(key[x]<key[y]) {
        tree[x][1]=merge(tree[x][1],y);
        update(x);
        return x;
    }
    else {
        tree[y][0]=merge(x,tree[y][0]);
        update(y);
        return y;
    }
}
void split(int now,int k,int &x,int &y) {//根据插入数的val值,把树分为小于等于k的,和大于k的 
    if (!now) x=y=0;//指针为空 
    else {
        if (val[now]<=k)
            x=now,split(tree[now][1],k,tree[now][1],y);//访问右子树 
        else
            y=now,split(tree[now][0],k,x,tree[now][0]);//访问左子树 
        update(now);
    }
}
int kth(int now,int k) {
    while(1) {
        if (k<=siz[tree[now][0]])
            now=tree[now][0];
        else
        if (k==siz[tree[now][0]]+1)
            return now;
        else
            k-=siz[tree[now][0]]+1,now=tree[now][1];
    }
}
int main() {
    //srand((unsigned)time(NULL));
    int T,op,x,y,z,a,b,root=0;
    scanf("%d",&T);
    while(T--) {
        op=read(),a=read();
        if (op==1) {
            split(root,a,x,y);
            root=merge(merge(x,make_new(a)),y);
        }
        else
        if (op==2) {
            split(root,a,x,z);
            split(x,a-1,x,y);
            y=merge(tree[y][0],tree[y][1]);
            root=merge(merge(x,y),z);
        }
        else if (op==3) {
            split(root,a-1,x,y);
            printf("%d
",siz[x]+1);
            root=merge(x,y);
        }
        else if (op==4)
            printf("%d
",val[kth(root,a)]);
        else
        if (op==5) {
            split(root,a-1,x,y);
            printf("%d
",val[kth(x,siz[x])]);
            root=merge(x,y);
        }
        else {
            split(root,a,x,y);
            printf("%d
",val[kth(y,1)]);
            root=merge(x,y);
        }
    }
    return 0;
}
treap

树链剖分(树上求和/树上最值)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 using namespace std;
  5 const int MAXN=2*1e6+10;
  6 #define ls k<<1
  7 #define rs k<<1|1
  8 inline int read() {
  9     char c=getchar();
 10     int x=0,f=1;
 11     while(c<'0'||c>'9') {
 12         if(c=='-')f=-1;
 13         c=getchar();
 14     }
 15     while(c>='0'&&c<='9') 
 16         x=x*10+c-'0',c=getchar();
 17     return x*f;
 18 }
 19 struct node {
 20     int u,v,nxt;
 21 } edge[MAXN];
 22 int head[MAXN];
 23 int num=1;
 24 struct Tree {
 25     int l,r,w,siz,f;
 26 } T[MAXN];
 27 int N,M,root,MOD,cnt=0,a[MAXN],b[MAXN];
 28 inline void AddEdge(int x,int y) {
 29     edge[num].u=x;
 30     edge[num].v=y;
 31     edge[num].nxt=head[x];
 32     head[x]=num++;
 33 }
 34 int deep[MAXN],fa[MAXN],son[MAXN],tot[MAXN],top[MAXN],idx[MAXN];
 35 int dfs1(int now,int f,int dep) {
 36     deep[now]=dep;
 37     fa[now]=f;
 38     tot[now]=1;
 39     int maxson=-1;
 40     for(int i=head[now]; i!=-1; i=edge[i].nxt) {
 41         if(edge[i].v==f) continue;
 42         tot[now]+=dfs1(edge[i].v,now,dep+1);
 43         if(tot[edge[i].v]>maxson) maxson=tot[edge[i].v],son[now]=edge[i].v;
 44     }
 45     return tot[now];
 46 }
 47 void update(int k) {
 48     T[k].w=(T[ls].w+T[rs].w+MOD)%MOD;
 49 }
 50 void Build(int k,int ll,int rr) {
 51     T[k].l=ll;
 52     T[k].r=rr;
 53     T[k].siz=rr-ll+1;
 54     if(ll==rr) {
 55         T[k].w=a[ll];
 56         return ;
 57     }
 58     int mid=(ll+rr)>>1;
 59     Build(ls,ll,mid);
 60     Build(rs,mid+1,rr);
 61     update(k);
 62 }
 63 void dfs2(int now,int topf) {
 64     idx[now]=++cnt;
 65     a[cnt]=b[now];
 66     top[now]=topf;
 67     if(!son[now]) return ;
 68     dfs2(son[now],topf);
 69     for(int i=head[now]; i!=-1; i=edge[i].nxt)
 70         if(!idx[edge[i].v])
 71             dfs2(edge[i].v,edge[i].v);
 72 }
 73 void pushdown(int k) {
 74     if(!T[k].f) return ;
 75     T[ls].w=(T[ls].w+T[ls].siz*T[k].f)%MOD;
 76     T[rs].w=(T[rs].w+T[rs].siz*T[k].f)%MOD;
 77     T[ls].f=(T[ls].f+T[k].f)%MOD;
 78     T[rs].f=(T[rs].f+T[k].f)%MOD;
 79     T[k].f=0;
 80 }
 81 void IntervalAdd(int k,int ll,int rr,int val) {
 82     if(ll<=T[k].l&&T[k].r<=rr) {
 83         T[k].w+=T[k].siz*val;
 84         T[k].f+=val;
 85         return ;
 86     }
 87     pushdown(k);
 88     int mid=(T[k].l+T[k].r)>>1;
 89     if(ll<=mid)    IntervalAdd(ls,ll,rr,val);
 90     if(rr>mid)    IntervalAdd(rs,ll,rr,val);
 91     update(k);
 92 }
 93 void TreeAdd(int x,int y,int val) {
 94     while(top[x]!=top[y]) {
 95         if(deep[top[x]]<deep[top[y]]) swap(x,y);
 96         IntervalAdd(1,idx[ top[x] ],idx[x],val);
 97         x=fa[ top[x] ];
 98     }
 99     if(deep[x]>deep[y])    swap(x,y);
100     IntervalAdd(1,idx[x],idx[y],val);
101 }
102 int IntervalSum(int k,int ll,int rr) {
103     int ans=0;
104     if(ll<=T[k].l&&T[k].r<=rr)
105         return T[k].w;
106     pushdown(k);
107     int mid=(T[k].l+T[k].r)>>1;
108     if(ll<=mid) ans=(ans+IntervalSum(ls,ll,rr))%MOD;
109     if(rr>mid)  ans=(ans+IntervalSum(rs,ll,rr))%MOD;
110     return ans;
111 }
112 void TreeSum(int x,int y) {
113     int ans=0;
114     while(top[x]!=top[y]) {
115         if(deep[top[x]]<deep[top[y]]) swap(x,y);
116         ans=(ans+IntervalSum(1,idx[ top[x] ],idx[x]))%MOD;
117         x=fa[ top[x] ];
118     }
119     if(deep[x]>deep[y]) swap(x,y);
120     ans=(ans+IntervalSum(1,idx[x],idx[y]))%MOD;
121     printf("%d
",ans);
122 }
123 int main() {
124     memset(head,-1,sizeof(head));
125     N=read(); M=read();
126     root=read();
127     MOD=read();
128     for(int i=1; i<=N; i++) b[i]=read();
129     for(int i=1; i<=N-1; i++) {
130         int x=read(),y=read();
131         AddEdge(x,y);
132         AddEdge(y,x);
133     }
134     dfs1(root,0,1);
135     dfs2(root,root);
136     Build(1,1,N);
137     while(M--) {
138         int opt=read(),x,y,z;
139         if(opt==1) {
140             x=read();
141             y=read();
142             z=read();
143             z=z%MOD;
144             TreeAdd(x,y,z);
145         } else if(opt==2) {
146             x=read();
147             y=read();
148             TreeSum(x,y);
149         } else if(opt==3) {
150             x=read(),z=read();
151             IntervalAdd(1,idx[x],idx[x]+tot[x]-1,z%MOD);
152         } else if(opt==4) {
153             x=read();
154             printf("%d
",IntervalSum(1,idx[x],idx[x]+tot[x]-1));
155         }
156     }
157     return 0;
158 }
sp

link cut tree

  1 #include<cstdio>
  2 #include<algorithm>
  3 const int maxn = 320007;
  4 inline int read() {
  5     int x=0,f=1;char c=getchar();
  6     while(c<'0'||c>'9') {
  7         if(c=='-')f=-1;c=getchar();
  8     }
  9     while(c<='9'&&c>='0') {
 10         x=x*10+c-'0',c=getchar();
 11     }
 12     return x*f;
 13 }
 14 #define lc ch[x][0]
 15 #define rc ch[x][1]
 16 bool rev[maxn];
 17 int stack[maxn],top;
 18 int ans[maxn],v[maxn];
 19 int fa[maxn],ch[maxn][2];
 20 bool isroot(int x) {
 21     return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;
 22 }
 23 void update(int x){
 24     ans[x]=ans[lc]^ans[rc]^v[x];
 25 }
 26 void pushdown(int x) {
 27      if(rev[x]) {
 28         rev[x]=0;rev[lc]^=1;rev[rc]^=1;
 29         std::swap(lc,rc);
 30      }
 31      return;
 32 }
 33 void rotate(int x) {
 34     int y=fa[x],z=fa[y],d=(ch[y][1]==x)^1;
 35     if(!isroot(y)) ch[z][ch[z][1]==y]=x;
 36     fa[x]=z;
 37     ch[y][d^1]=ch[x][d],fa[ch[x][d]]=y;
 38     ch[x][d]=y;fa[y]=x;
 39     return update(y),update(x);
 40 }
 41 void splay(int x) {
 42     stack[++top]=x;
 43     for(int i=x;!isroot(i);i=fa[i]) 
 44         stack[++top]=fa[i];
 45     while(top)pushdown(stack[top--]);
 46     while(!isroot(x)) {
 47         int y=fa[x],z=fa[y];
 48         if(!isroot(y)) {
 49             if(ch[y][1]==x^ch[z][1]==y)rotate(x);
 50             else rotate(y);
 51         }
 52         rotate(x);
 53     }
 54     return ;
 55 }
 56 void access(int x) {
 57     for(int i=0;x;i=x,x=fa[x]) {
 58         splay(x),ch[x][1]=i,update(x);
 59     }
 60     return ;
 61 }
 62 void makeroot(int x) {
 63     access(x);splay(x);rev[x]^=1;
 64     return;
 65 }
 66 void split(int x,int y) {
 67     makeroot(x),access(y);return splay(y);
 68 }
 69 void cut(int x,int y) {
 70     split(x,y);
 71     ch[y][0]=fa[ch[y][0]]=0;
 72     return;
 73 }
 74 void link(int x,int y) {
 75     makeroot(x),fa[x]=y;return splay(x);
 76 }
 77 int find(int x) {
 78     for(access(x),splay(x);ch[x][0];x=ch[x][0]);
 79     return x;
 80 }
 81 int query(int x,int y) {
 82     split(x,y);
 83     return ans[y];
 84 }
 85 void modify(int x,int w) {
 86     access(x),splay(x),v[x]=w;
 87     return update(x);
 88 }
 89 int main() {
 90     int n,m;
 91     n=read(),m=read();
 92     for(int i=1;i<=n;++i) {
 93         v[i]=read();ans[i]=v[i];
 94     }
 95     for(int op,x,y,i=1;i<=m;++i) {
 96         op=read(),x=read(),y=read();
 97         if(!op) 
 98             printf("%d
",query(x,y));
 99         else if(op==1) {
100             if(find(x)!=find(y)) link(x,y);
101         }
102         else if(op==2) {
103             if(find(x)==find(y))cut(x,y);
104         }
105         else modify(x,y);
106     }
107     return 0;
108 }
lct

左偏树

#include<cstdio>
#include<algorithm>

inline int read() {
    int x=0;char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
    return x;
}
const int maxn = 100010;
struct node {
    int fa,dis,key,ch[2];
    node() {
        key=fa=dis=0;
    }
}tree[maxn];
inline int ls(int x) {return tree[x].ch[0];}
inline int rs(int x) {return tree[x].ch[1];}
int n,m;
int find(int x) {
    if(tree[x].fa)  return find(tree[x].fa);
    else return x;
}
inline void update(int x) {
    tree[x].dis=tree[tree[x].ch[1]].dis+1;
}
int merge(int x,int y) {
    if(!x||!y)return x+y;
    if(tree[x].key>tree[y].key||(tree[x].key==tree[y].key&&x>y))std::swap(x,y);
    tree[x].ch[1]=merge(tree[x].ch[1],y);
    tree[tree[x].ch[1]].fa=x;
    if(tree[tree[x].ch[1]].dis>tree[tree[x].ch[0]].dis)std::swap(tree[x].ch[0],tree[x].ch[1]);
    update(x);
    return x;
}
void delet(int x) {
    int now=tree[x].fa;int top=merge(tree[x].ch[1],tree[x].ch[0]);
    tree[top].fa=now;tree[x].key=-1;
    while(now) {
        if(tree[tree[now].ch[0]].dis<tree[tree[now].ch[1]].dis)std::swap(tree[now].ch[0],tree[now].ch[1]);
        if(tree[now].dis==tree[tree[now].ch[1]].dis+1)return;
        tree[now].dis=tree[tree[now].ch[1]].dis+1;
        now=tree[now].fa;
    }
}
int main() {
    n=read(),m=read();
    for(int i=1;i<=n;++i) tree[i].key=read();
    while(m--) {
        int op=read();
        if(op==1) {
            int x=read(),y=read();
            if(tree[x].key==-1||tree[y].key==-1||x==y)continue;
            merge(find(x),find(y));
        }
        else {
            int x=read();
            if(tree[x].key==-1)puts("-1");
            else x=find(x),
            printf("%d
",tree[x].key),
            delet(x);
        }
    }
    return 0; 
}
左偏树

单调队列(两端扩展最大距离(最小值))

#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long 
const int maxn= 2000007;
#ifdef WIN32
#define lld "I64d"
#else
#define lld "lld"
#endif
inline int read() {
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();return x;
} 
int a[maxn],b[maxn];
int l[maxn],r[maxn],tmp[maxn],q[maxn];
int n,m;
void work(int c[] ,int d[]) {
    q[1]=c[1]; tmp[1]=1;
    int head=1,tail=1;
    for(int i=2;i<=n;++i) {
        while(head<=tail&&q[tail]>c[i]) d[tmp[tail--]]=i-1;
        q[++tail]=c[i];
        tmp[tail]=i;
       }
       while(head<=tail) d[tmp[head++]]=n;
}
int main() {
    LL ans=0;
    n=read();
    for(int i=1;i<=n;++i) 
        a[i]=read(),b[n-i+1]=a[i];
    work(a,r);
    work(b,l);
    for(int i=1;i<=n;++i) tmp[i]=l[i];
    for(int i=1;i<=n;++i) l[n-i+1]=n-tmp[i]+1;
    for(int i=1;i<=n;++i) ans=max(ans,1ll*a[i]*(r[i]-l[i]+1));
    printf("%lld
",ans);
    return 0;
}

单调队列
单调队列

 并查集安置合并

int cnt = 0 ,fa[maxn],deep[maxn],siz[maxn],v[maxn]; 
int find(int x)  { 
    if(fa[x] != x) { 
        int f = find(fa[x]); 
        deep[x] = deep[fa[x]] + 1; 
        return f;   
    } else return x; 
} 
void Union(int x,int y,int C) { 
    int f1 = find(x),f2 = find(y);  
    if(f1 == f2) return ;  
    if(siz[f1] > siz[f2]) fa[f2] = f1,v[f2] = C,siz[f1] += siz[f2]; 
    else fa[f1] = f2,v[f1] = C,siz[f2] += siz[f1]; 
} 
int query(int x,int y) {
    int f1 = find(x),f2 = find(y); 
    if(f1 != f2)return 0; 
    int ret = 0 ; 
    for(;x != y;) { 
        if(deep[x] < deep[y]) swap(x,y); 
        ret = max(ret,v[x]),x = fa[x]; 
    } return ret; 
} 
并查集

AC自动机

fail树

#include<queue> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#define LL long long
inline int read() { 
    int x = 0,f = 1;char c = getchar(); 
    while(c < '0'||c > '9')c = getchar(); 
    while(c <= '9' &&c >= '0')x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
} 
#define LL long long 
int n; 
const int maxn = 1000097; 
char a[maxn];
int sz,ch[maxn][27];LL cnt[maxn]; 
struct node {
    int v,next; 
} edge[maxn << 1]; 
int num,head[maxn],loc[maxn]; 
inline void add_edge(int u,int v) { edge[++ num].v = v ;edge[num].next = head[u];head[u] = num; } 
int insert(char *t) { 
    int len = strlen(t); 
    int now = 0; 
    for(int i = 0;i < len;++ i) { 
        int  s = t[i] - 'a'; 
        if(!ch[now][s]) ch[now][s] = ++ sz; 
        now = ch[now][s]; cnt[now] ++; 
    } 
    return now; 
} 
int fail[maxn],q[maxn]; 
void get_fail(int l = 0,int r = 0 ) { 
    for(int i = 0;i <= 25;++ i)if(ch[0][i]) q[++ r] = ch[0][i]; 
    while(l < r) { 
        int u = q[++ l]; 
        for(int i = 0;i <= 25;++ i) { 
            int v = ch[u][i]; 
            if(v) fail[v] = ch[fail[u]][i],q[++ r] = v; 
            else ch[u][i] = ch[fail[u]][i]; 
        } 
    } 
} 
void dfs(int x,int fa = 0) {  
    for(int i = head[x];i;i = edge[i].next) {  
        int v = edge[i].v;  
        if(v != fa) {dfs(v,x),cnt[x] += cnt[v];}   
    }   
}  
int main() { 
    n = read();  
    for(int i = 1;i <= n;++ i) {  
        scanf("%s",a);  
        loc[i] = insert(a);  
    }  
    get_fail();  
    for(int i = 1;i <= sz;++ i) { 
        add_edge(fail[i],i); 
    } 
    dfs(0); 
    for(int i = 1;i <= n;++ i) { 
        printf("%d
",cnt[loc[i]]); 
    } 
    return 0;
}
ACfail树
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int  maxn = 1000001;
int n;
char s[maxn];

int ans=0;
struct Aho_Corasick_automato{
    int sz;
    int ch[maxn][26];
    int val[maxn];
    int last[maxn];
    int fail[maxn];
    int num;
    void init() {
        memset(ch[0],0,sizeof(ch[0]));
        sz=1;
    }
    void insert(char *s) {
        int len=strlen(s);
        int u=0;
        for(int i=0; i<len; ++i) {
            int v=(s[i]-'a');
            if(!ch[u][v]) {
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][v]=sz++;
            }
            u=ch[u][v];
        }
        val[u]++;
    }
    void get_fail() {
        fail[0]=0;
        queue<int>que;
        for(int i=0; i<26; i++) {
            int u=ch[0][i];
            if(u) {
                fail[u]=0;
                que.push(u);
            }
        }
        while(!que.empty()) {
            int u=que.front(); 
            que.pop();
            for(int i=0; i<26; i++) {
                int v=ch[u][i];
                if(!v) {
                    ch[u][i]=ch[fail[u]][i];
                    continue;
                }
                que.push(v);
                int k=fail[u];
                fail[v]=ch[k][i];
                last[v]=val[fail[v]] ? fail[v] : last[fail[v]];
            }
        }
    }
    void work(int x) {
        if(val[x]) {
            ans+=val[x];
            val[x]=0;
            work(last[x]);
        }
    }
    void find(char *s) {
        int len=strlen(s);
        int u=0;
        for(int i=0; i<len; i++) {
            int v=(s[i]-'a');
            if(!ch[u][v])u=fail[u];
            while(u&&!ch[u][v])
                u=fail[u];
            u=ch[u][v];
            if(val[u])
                work(u);
            else if(last[u])
                work(last[u]);
        }   
    }       
} ac;

int main() {

    scanf("%d",&n);
    ac.init();
    for(int i=1; i<=n; i++) {
        scanf("%s",s);
        ac.insert(s);
    }
    ac.get_fail();
    scanf("%s",s);
    ac.find(s);
    printf("%d
",ans);
    return 0;
}
AC自动机

虚树

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar(); } 
    while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
} 
const int maxn = 300007; 
int n; 
struct node { 
    int v,next; 
} edge[maxn << 1],e[maxn << 1];   
int head[maxn],num,h[maxn],num1,deep[maxn];  
inline void add(int u,int v) { if(u == v) return; 
    e[++ num1].v = v;e[num1].next = h[u];h[u] = num1; 
} 
inline void add_edge(int u,int v ) { 
    edge[++ num].v = v;edge[num].next = head[u];head[u] = num; 
} 

int dfn[maxn],cnt = 0,dad[maxn][20],size[maxn]; 

void dfs(int x,int fa) { 
    size[x] = 1; 
    dfn[x] = ++ cnt; deep[x] = deep[fa] + 1; dad[x][0] = fa; 
    for(int i = 0;dad[x][i];++ i) 
        dad[x][i + 1] = dad[dad[x][i]][i]; 
    for(int i = head[x];i;i = edge[i].next ) { 
         int v = edge[i].v; 
         if(v == fa) continue; 
         dfs(v,x); 
        size[x] += size[v]; 
    } 
} 
int lca(int x,int y) {
    if(deep[x] > deep[y]) std::swap(x,y); 
    for(int i = 18;i >= 0;-- i)if(deep[x] <= deep[dad[y][i]]) y = dad[y][i]; 
        if(x == y) return x; 
    for(int i = 18;i >= 0;-- i) if(dad[x][i] != dad[y][i])x = dad[x][i],y = dad[y][i];  
    return x == y ? x : dad[x][0]; 
} 

inline bool cmp(int x,int y) {return dfn[x] < dfn[y];} 
int c[maxn],rem[maxn],Dfn,bel[maxn];  

int dis(int x,int y) { 
    return deep[x] + deep[y] - 2 * deep[lca(x,y)]; 
} 

void get_fri(int x) { 
    c[++ Dfn] = x;rem[x] = size[x];  
    for(int i = h[x];i;i = e[i].next ) { 
        int v = e[i].v; 
        get_fri(v); 
        if(!bel[v]) continue; 
        int t1 = dis(bel[v],x),t2 = dis(bel[x],x); 
        if((t1 == t2 && bel[v] < bel[x]) || t1 < t2 || !bel[x]) bel[x] = bel[v]; 
    } 
}   
void get_sec(int x) { 
    for(int i = h[x];i;i = e[i].next) { 
        int v = e[i].v; 
        int t1 = dis(bel[x],v),t2 = dis(bel[v],v); 
        if((t1 == t2 && bel[v] > bel[x]) || t1 < t2 || !bel[v])bel[v] = bel[x]; 
        get_sec(v); 
    }       
} 

int dp[maxn]; 
void divide(int a,int b) { 
    int x = b,mid = b; 
    for(int i = 18;i >= 0;-- i) 
        if(deep[dad[x][i]] > deep[a]) x = dad[x][i]; 
    rem[a] -= size[x]; 
    if(bel[a] == bel[b]) {
        dp[bel[a]] += size[x] - size[b]; return; 
    }  
    for(int i = 18;i >= 0;-- i) { 
        if(deep[dad[mid][i]] <= deep[a]) continue; 
        int t1 = dis(bel[a],dad[mid][i]),t2 = dis(bel[b],dad[mid][i]); 
        if(t1 > t2 || (t1 == t2 && bel[b] < bel[a]))mid = dad[mid][i]; 
    } 
    dp[bel[a]] += size[x] - size[mid]; 
    dp[bel[b]] += size[mid] - size[b]; 
} 
int htmp[maxn],stack[maxn],H[maxn]; 
void solve(int k = 0) { 
    int top;memset(h,0,sizeof h);
    top = Dfn = 0;
    k = read(); 
    for(int i = 1;i <= k;++ i) htmp[i] = H[i] = read(); 
    for(int i = 1;i <= k;++ i) bel[H[i]] = H[i] ; 
    std::sort(H + 1,H + k + 1,cmp); 
    stack[++ top] = 1; 
    for(int i = 1;i <= k;++ i) { 
        int x = H[i],f = lca(stack[top],x); 
        while("tle") { 
            if(deep[f] >= deep[stack[top - 1]]) { 
                add(f,stack[top --]); 
                if(stack[top] != f) stack[++ top] = f; 
                break;  
            }  add(stack[top - 1],stack[top]);top --;  
        }  if(stack[top] != x) stack[++ top] = x;   
    } 
    while(top - 1) add(stack[top - 1],stack[top]),top --; 
    get_fri(1); 
    get_sec(1); 
    for(int i = 1;i <= Dfn;++ i)  
        for(int j = h[c[i]];j;j = e[j].next) { 
                divide(c[i],e[j].v);        
        } 
    for(int i = 1;i <= Dfn;++ i) dp[bel[c[i]]] += rem[c[i]]; 
        for(int i = 1;i <= k;++ i) printf("%d ",dp[htmp[i]]);puts(""); 
    for(int i = 1;i <= Dfn;++ i) dp[c[i]] = bel[c[i]] = H[c[i]] = rem[c[i]] = 0; 
    num1 = 0; 
} 
int main() { 
    n = read(); 
    for(int u,v,i = 1;i < n;++ i) { 
        u = read(),v = read(); 
        add_edge(u,v);add_edge(v,u); 
    } 
    dfs(1,0);   
    int q = read() ; 
    for(;q --;)  
    solve(); 
    return 0; 
} 
 
虚数

排序

快排+求k大值

int qsort(int *a,int l,int r)
{
    int tmp = a[l],pos = l;
    int i = l, j = r;
    while (i<j)
    {
        while (i<j&&a[j]>tmp) j--;
        if (i<j)
        {
            a[pos] = a[j];
            pos = j;
        }
        while (i<j&&a[i]<tmp) i++;
        if (i<j)
        {
            a[pos] = a[i];
            pos = i;
        }
    }
    a[pos] = tmp;
    return pos;
}
int findkth(int *a,int n,int k)
{
    int l = 0,r = n-1;
    while (1)
    {
        int pos = qsort(a,l,r);
        if (pos==n-k) return a[pos];
        else if (pos<n-k) l = pos+1;
        else r = pos-1;
    }
}

快速排序求第k大的数
q_sort

归并+求逆序对

#include<cstdio>

int n,ans;
int a[500100],b[500100];    //a原数组,b暂存数组 

void merge_sort(int l,int r)    //归并 
{
    if (l==r) return ;    //一个数不用排序 
    int m = (l+r)>>1;
    merge_sort(l,m);    //排序左边 
    merge_sort(m+1,r);    //排序右边 
    int i = l, j = m+1, k = l ;    //i左边最小的位置,j右边最小的位置 
    while (i<=m && j<=r)
        if (a[i]<=a[j]) b[k++] = a[i++];
        else ans += m-i+1, b[k++] = a[j++];    //加入右半段时,逆序对数增加 
    while (i<=m) b[k++] = a[i++];    //加入左边剩余的数 
    while (j<=r) b[k++] = a[j++];    //加入右边剩余的数
    for (i=l; i<=r; ++i) a[i] = b[i];    //从暂存数组中赋值 
}

int main()
{
    scanf("%d",&n);
    for (int i=1; i<=n; ++i)
        scanf("%d",&a[i]);
    merge_sort(1,n);
    printf("%d",ans);
    return 0;
}
m_sort

数学

组合数递推

C[1][0] = C[1][1] = 1;
for (int i=2; i<=N; i++)
{
    C[i][0] = 1;
    for (int j=1; j<=N; j++)
        C[i][j] = C[i-1][j]+C[i-1][j-1];
}
组合数递推公式

线性筛求莫比乌斯函数(mu)

void get()
{
    int n = 100;
    mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!ol[i])prime[++num]=i,cout<<i<<" ",mu[i]=-1;
        for(int j=1;j<=num&&j*prime[i]<=n;j++)
        {
            ol[i*prime[j]]=1;
            if((i%prime[j])==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            mu[i*prime[j]]=-mu[i];
        }
    }
    cout<<num<<endl;
}
莫比乌斯

 根n求欧拉函数

int getphi(int x){
    int ret=1;
    for(int i=1;prime[i]*prime[i]<=x;i++){
        if(x%prime[i]==0)
        {
            ret*=prime[i]-1;
            x/=prime[i];
            while(x%prime[i]==0)
            x/=prime[i],ret*=prime[i];
        }
    }
    if(x>1) ret*=x-1;
    return ret;
}
求欧拉

矩阵乘法(fib

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

const int mod = 1e9+7;
const int N = 2;

struct Matrix{
    int a[N][N];
    Matrix(){
        this->clear();
    }
    void clear(){
        memset(a,0,sizeof(a));
    }
    void setone(){
        this->clear();
        for (int i=0; i<N; ++i)
            a[i][i] = 1;
    }
    Matrix operator * (const Matrix &x) const 
    {
        Matrix c;
        for (int k=0; k<N; k++)
            for (int i=0; i<N; ++i)
                for (int j=0; j<N; ++j)
                    c.a[i][j] = (c.a[i][j]+1ll*a[i][k]*x.a[k][j])%mod;
        return c;
    }
};

int fibn(int n)
{
    Matrix x,s;
    x.a[0][0] = x.a[0][1] = x.a[1][0] = 1;
    s.setone();
    for (; n; n>>=1)
    {
        if (n&1) s = s*x;
        x = x*x; 
    }
    return (s.a[0][0]+s.a[0][1])%mod;
}
int main()
{
    int n;
    while (~scanf("%d",&n))
    {
        if (n==1||n==2) puts("1");
        else printf("%d
",fibn(n-2));
    }
    return 0;
}
矩阵乘法快速幂求斐波那契

逆元相关:

线性求逆元

#include<cstdio>
#include<algorithm>
#define LL long long
LL inv[3000053];
//int inv[MAXN]; 
void INV(int a,int p) 
{
    inv[1] = 1;
    for (int i=2; i<=a; ++i)
        inv[i] = (LL)((p-(p/i)%p)%p*inv[p%i])%p; 
}


int main() {
    int n,p;
    scanf("%d%d",&n,&p);
    INV(n,p);
    for(int i=1;i<=n;++i) 
        printf("%d
",inv[i]);
    return 0;
}
线性求逆元
#include<cstdio>
#include<algorithm>
#define LL long long
LL inv[3000053];
//int inv[MAXN]; 
void INV(int a,int p) 
{
    inv[1] = 1;
    for (int i=2; i<=a; ++i)
        inv[i] = (LL)((p-(p/i)%p)%p*inv[p%i])%p; 
}


int main() {
    int n,p;
    scanf("%d%d",&n,&p);
    INV(n,p);
    for(int i=1;i<=n;++i) 
        printf("%d
",inv[i]);
    return 0;
}
线性求逆元

 高斯消元

void gauss() {
    int t;
    for(int i=1;i<=n;++i) {
        t=i;
        for(int j=i+1;j<=n;++j) if(loc[j][i]>loc[t][i]) t=j;
        if(t!=i) for(int j=i;j<=n+1;++j) std::swap(loc[t][j],loc[i][j]);
        for(int j=i+1;j<=n;++j) {
            double tmp=loc[i][i]/loc[j][i];
            for(int k=i+1;k<=n+1;++k) loc[j][k]=loc[i][k]-tmp*loc[j][k];
        }
    }
    for(int i=n;i>=1;--i) { 
        for(int j=i+1;j<=n;++j) loc[i][n+1]-=x[j]*loc[i][j];
        x[i]=loc[i][n+1]/loc[i][i];
    }
}
guass消元

扩展欧几里得求逆元

#include<cstdio>

int exgcd(int a,int b,int &x,int &y)
{
    if (b==0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int r = exgcd(b,a%b,x,y);
    int tmp = x;
    x = y;
    y = tmp-a/b*y;
    return r;
}

int main()
{
    //gcd(a,p)==1
    int a,p,r,x,y;
    while (scanf("%d%d",&a,&p)!=EOF)
    {
        r = exgcd(a,p,x,y);
        printf("%d",(x%p+p)%p);
    }
    return 0;
}
扩展欧几里得求逆元

数论bsgs+exgcd+q_pow

1 #include<cstdio>
  2 #include<map>
  3 #include<cmath>
  4 using namespace std;
  5 
  6 typedef long long LL;
  7 int T,L;
  8 
  9 LL qpow(LL a,LL p,LL mod)
 10 {
 11     LL base=a;
 12     LL sum=1;
 13     while(p!=0)
 14     {
 15         if(p&1)
 16         sum=(sum*base)%mod;
 17         base=(base*base)%mod;
 18         p>>=1;
 19     }
 20     return sum;
 21 }
 22 
 23 void work1()
 24 {
 25     LL y,z,p;
 26     scanf("%lld%lld%lld",&y,&z,&p);
 27     printf("%lld
",qpow(y,z,p)%p);
 28     return ;
 29 }
 30 
 31 
 32 void exgcd(int a,int b,LL &d,LL &x,LL &y)
 33 {
 34     if(!b){d=a;x=1;y=0;return ;}
 35     exgcd(b,a%b,d,y,x);
 36     y-=x*(a/b);
 37 }
 38 LL gcd(LL a,LL b)
 39 {
 40     if(!b) return a;
 41     return gcd(b,a%b);
 42 }
 43 void work2()
 44 {
 45     LL a,b,y,z,x,d,mod;
 46     scanf("%lld%lld%lld",&y,&z,&mod);
 47     a=y;
 48     b=-mod;
 49     d=gcd(a,b);
 50     if(z%d)
 51     {
 52         printf("Orz, I cannot find x!
");
 53         return ;
 54     }
 55     a/=d;b/=d;z/=d;
 56     exgcd(a,b,d,x,y);
 57     x*=z;x%=b;
 58     while(x<0)    x+=b;
 59     printf("%lld
",x);
 60 }
 61 
 62 
 63 map<LL,LL>mp;
 64 void work3()
 65 {
 66     mp.clear();
 67     LL y,z,q,p;
 68     scanf("%lld%lld%lld",&y,&z,&p);
 69     y%=p;
 70     if(!y&&!z)
 71     {
 72         puts("1");return ;
 73     }
 74     if(!y)
 75     {
 76         printf("Orz, I cannot find x!
");
 77         return;
 78     }
 79     LL pos=ceil(sqrt(p));
 80     LL ans;
 81     for(LL i=0;i<=pos;i++)
 82     {
 83         if(i==0)
 84         {
 85             ans=z%p;
 86             mp[ans]=1;
 87             continue;
 88         }
 89         ans=(ans*y)%p;
 90         mp[ans]=i;
 91     }
 92     ans=1;
 93     LL t=qpow(y,pos,p);
 94     for(LL i=1;i<=pos;i++)
 95     {
 96         ans=(ans*t)%p;
 97         if(mp[ans])
 98         {
 99             LL b=i*pos-mp[ans];
100             printf("%d
",(b%p+p)%p);
101             return ;
102         }
103     }
104     printf("Orz, I cannot find x!
");
105 }
106 int main()
107 {
108     scanf("%d%d",&T,&L);
109     if(L==1)
110     for(int i=1;i<=T;i++)
111     work1();
112     if(L==2)
113     for(int i=1;i<=T;i++)
114     work2();
115     if(L==3)
116     for(int i=1;i<=T;i++)
117     work3();
118     return 0;
119 }
bsgs

同于方程组:

中国剩余定理

/*long long gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}*/
#include<cstdio>
#define ll long long
//扩展欧几里得算法 
void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(b==0){
        d=a;
        x=1,y=0;
    }
    else{//else不能省略 
        gcd(b,a%b,d,y,x);
        y-=(a/b)*x;
    }
}
//中国剩余定理 
ll China(int n,ll *m,ll *a)
{
    ll M=1,d,y,x=0;
    for(int i=0;i<n;i++) M*=m[i];
    for(int i=0;i<n;i++){
        ll w=M/m[i];
        gcd(m[i],w,d,d,y);
        x=(x+y*w*a[i])%M;
    }
    return (x+M)%M;
}
ll m[15],a[15];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%lld%lld",&m[i],&a[i]);
    printf("%lld",China(n,m,a));
}
crt

扩展欧几里得解法

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

#define LL long long
LL a[6],r[6];
int n;

LL exgcd(LL a,LL b,LL &x,LL &y) {
    if(b==0) {x=1,y=0;return a;}
    LL tmp=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return tmp;
}
LL solve() {
    LL M=a[1],R=r[1],x,y,d;
    for(int i=2;i<=4;i++) {
        d=exgcd(M,a[i],x,y);
        if((R-r[i])%d!=0) return -1;
        x=(R-r[i])/d*x%a[i];
        R-=x*M;
        M=M/d*a[i];
        R%=M;
    }
    return (R%M+M)%M;
}

int main() {
    for(int i=1; i<=4; i++)
    scanf("%lld%lld",&a[i],&r[i]);
    printf("%lld
",solve());
    return 0;
}
exgcd

 矩阵快速幂

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
int n;LL k;
const int mod = 1e9+7;
struct Matrix {
    LL a[107][107];
    Matrix() {
        std::memset(a,0,sizeof a);
    }
    Matrix operator * (const Matrix & y)const   {
        Matrix ans;
        for(int i=1;i<=n;++i) {
            for(int j=1;j<=n;++j) {
                for(int k=1;k<=n;++k) {
                    ans.a[i][j]=(ans.a[i][j]+((a[i][k]%mod)*(y.a[k][j]%mod)))%mod;
                }
            }
        }
        return ans;
    }
        
}pre,ans;
void pow(LL k) {
    for(int i=1;i<=n;++i) 
        ans.a[i][i]=1;
    while(k) {
        if(k&1) ans=ans*pre;
        pre=pre*pre;
        k>>=1;
    }
    for(int i=1;i<=n;++i) {
        for(int j=1;j<=n;++j) {
            printf("%lld ",ans.a[i][j]);
        }
        puts("");
    }
    return ;
}
int main() {
    scanf("%d%lld",&n,&k);
    for(int i=1;i<=n;++i) {
        for(int j=1;j<=n;++j) {
            scanf("%d",&pre.a[i][j]);
        }
    }
    pow(k);
    return 0;
}
矩阵快速幂

 高消异或

#include<bits/stdc++.h> 
using namespace std; // 每天好心情从namespace开始 
const int maxn = 157; 
#define LL long long 
inline LL read() { 
    LL x = 0,f = 1;
    char c = getchar(); 
    while(c < '0' || c > '9'){if(c == '-')f = - 1;  c = getchar();}  
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
} 
int n; 
const int mod = 1000000007; 
long long A[100007]; 
int prime[100007],is[100007],num = -1; 
void getprime() { 
    for(int i = 2;i <= 2000;++ i) { 
        if(!is[i]) prime[++ num] = i;  
        for(int j = 0;j <= num && prime[j] * i <= 2000;++ j) { 
            is[i * prime[j]] = 1; 
            if(i % prime[j] == 0) break; 
        } 
    } 
} 
bitset<330>a[305]; 
int guass(int equ,int var) { 
    int r,c,t,j = 0; 
    for(r = c = 0;r < equ && c < var;++ r, ++c) { 
        for(t = r;t < equ;++ t) if(a[t][c]) break; 
        if(t == equ) { 
             r --;continue; 
        } else swap(a[t],a[r]); 
        for(int i = r + 1; i < equ;++ i) if(a[i][c]) a[i] ^= a[r]; 
    } 
    return var - r; 
} 
int solve() { 
    for(int i = 0; i < 305; i++) a[i].reset(); 
    for(int i = 0;i < n;++ i)  
        for(int j = 0;j <= num;++ j) { 
            LL tmp = A[i]; 
            if(tmp % prime[j] == 0) { 
                bool flag = 0; 
                while(tmp % prime[j] == 0) { 
                    tmp /= prime[j]; 
                    flag ^= 1; 
                } 
                a[j][i] = flag; 
            } 
        } 
    int zyy = guass(num + 1,n); 
    LL ret = 1; 
    for(int i = 1;i <= zyy;++ i)ret <<= 1,ret %= mod; 
    return ret - 1; 
} 
int main() { 
    getprime(); 
    int t = read(); 
    int cas = 0;  
    while(t --) { 
        ++ cas; 
        printf("Case #%d:
",cas); 
        n = read(); 
        for(int i = 0;i < n;++ i) A[i] = read();  
        printf("%d
",solve()); 
    } 
    return 0; 
} 
高消异或

反演

#include <queue> 
#include <cstdio> 
#include <algorithm> 
inline int read() { 
    int x = 0; 
    char c = getchar(); 
    while(c < '0' || c > '9')c = getchar();  
    while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar();
    return x; 
} 
const int mod = (1 << 31); 
const int maxn = 100007; 
int p[maxn],mu[maxn],mx; bool vis[maxn]; 
struct node { 
    int n,m,a,id; 
    bool operator < (const node & k)const { 
        return a < k.a; 
    } 
} q[maxn]; 
std::pair<int,int>F[maxn]; 
void getmu() { 
    int size = mx,num = 0; 
    mu[1] = 1; 
    for(int i = 2;i <= size;++ i) { 
        if(!vis[i]) p[++ num] = i,mu[i] = -1; 
        for(int j = 1;j <= num && i * p[j] <= size;++ j) {  
            vis[i * p[j]] = true; 
            if(i % p[j] == 0) { 
                mu[i * p[j]] = 0; break; 
            } mu[i * p[j]] = -mu[i];  
        } 
    } 
    for(int i = 1;i <= size;++ i) 
        for(int j = i;j <= size;j += i) 
            F[j].first += i; 
    for(int i = 1;i <= size;++ i)F[i].second = i; 
} 
int ans[maxn]; 
#define lowbit(x) x&(-x)
int bit[maxn << 1]; 
void add(int x,int num) { 
    for(int i = x;i <= mx; i += lowbit(i))bit[i] += num; 
} 
int query(int x) { 
    int ret = 0; 
    for(int i = x;i; i -= lowbit(i)) ret += bit[i]; 
    return ret; 
} 
void solve(int x) { 
    int n = q[x].n,m = q[x].m; 
    for(int i = 1,j;i <= q[x].n;i = j + 1) { 
        j = std::min(m / (m / i),n / (n/i)); 
        ans[q[x].id] += (n / i) * (m / i) * (query(j) - query(i - 1)); 
    } 
} 
int main() { 
    int k = read(); 
    for(int i = 1;i <= k;++ i) { 
        q[i].n = read(),q[i].m = read(),q[i].a = read(); 
        if(q[i].n > q[i].m) std::swap(q[i].n,q[i].m); 
        q[i].id = i; mx = std::max(mx,q[i].n); 
    } 
    getmu(); 
    std::sort(q + 1,q + k + 1); 
    std::sort(F + 1,F + mx + 1); 
    for(int i = 1,now = 0;i <= k;++ i) { 
        for(;now + 1 <= mx && F[now + 1].first <= q[i].a;) { 
            now ++; 
            for(int j = F[now].second;j <= mx;j += F[now].second) { 
                //printf("%d
",now); 
                add(j,F[now].first * mu[j / F[now].second]); 
            } 
        } 
        solve(i); 
    } 
    //printf("%d
",mod); 
    for(int i = 1;i <= k;++ i) { 
        printf("%d
",ans[i] & 0x7fffffff ); 
    } 
    return 0; 
}
反演

杂七杂八算法

二分查找+lower_bound(有序序列

int binary_search(int x,int y,int c)
{
    int l,r,mid;
    l = x; 
    r = y;
    while (l<r)
    {
        mid = (l+r)>>1;
        if (c<=a[mid]) r = mid;
        else l = mid+1;
    }
    return l;
}
/*------------------------------------*/
int find(int l,int r,int x)
{
    while (l<=r)
    {
        int mid = (l+r)>>1;
        if (a[mid]<=x) l = mid+1;
        else r = mid-1;
    }
    return l;
}
二分查找

lower_bound

 lower_bound(a+x,a+y+1,c)-a; 
lower_bound

莫队

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 100010;
int n,m,num,a[N];
struct data{
    int l,r,id,block;
}q[N];
int cnt[N],ans[N];

bool cmp(data a,data b)
{
    if(a.block==b.block) return a.r<b.r;
    return a.block < b.block;
}
int tmp;
/*void add(int x)
{
    cnt[a[x]]++;
    if(cnt[a[x]]==1)tmp++;
}
void del(int x)
{
    cnt[a[x]]--;
    if(!cnt[a[x]])tmp--;
}*/
void Solve()
{
    int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        while(l<q[i].l) del(l),l++;
        while(l>q[i].l) l--,add(l);
        while(r<q[i].r) r++,add(r);
        while(r>q[i].r) del(r),r--;
        ans[q[i].id]=tmp;
    }
}
int main()
{
    cin>>n;
    num=sqrt(n);
    for(int i=1;i<=n;i++)cin>>a[i];
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>q[i].l>>q[i].r;
        q[i].id=i;
        q[i].block=(q[i].l-1)/num+1;
    }
    sort(q+1,q+m+1,cmp);
    Solve();
    for(int i=1;i<=m;i++)
        printf("%d
",ans[i]);
    return 0;    
}
莫队

分块的构造??(假的

inline void divide(int x)
{
    for(int i=1;i<=x;i++)
    left[i]=right[i-1]+1,right[i]=i*x;
    right[x]=n;
    for(int i=1;i<=x;i++)
        for(int j=left[i];j<=right[i];j++)
        belong[j]=i;
    for(int i=n;i>=1;i--)
    {
        if(where[i]>right[belong[i]])out[i]=1;
        else out[i]=out[where[i]]+1,where[i]=where[where[i]];
    }
}

inline void query(int x)
{
    int ans=0;
    while(x<=n)
    {
        ans+=out[x],x=where[x];
    }
    printf("%d
",ans);
}

inline void modify(int x,int y)
{
    int i,j;
    int tmp=belong[x],l=left[tmp],r=right[tmp];
    a[x]=x+y;
    if(a[x]>r)out[x]=1,where[x]=a[x];
    else out[x]=out[a[x]]+1,where[x]=where[a[x]];
    for(i=x-1;i>=l;i--)
    {
        if(a[i]<=x)
        out[i]=out[a[i]]+1,where[i]=where[a[i]];
    }
}

    n=read();
    int x=sqrt(n);
    for(int i=1;i<=n;i++)
    a[i]=read(),where[i]=i+a[i],a[i]=where[i];
分块

 点分治

 #include<cstdio> 
#include<algorithm> 
inline int read() { 
    int x = 0,f = 1;
    char c = getchar(); 
    while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();} 
    while(c <= '9' &&c >= '0')x = x * 10 + c - '0',c = getchar(); 
    return x * f;   
} 
const int maxw = 2000007;
const int maxn = 160000 + 10000 + 7;  
struct Query {
    int x,y,type,w,aid; 
    Query(int Type = 0,int X = 0,int Y = 0,int W = 0,int Aid = 0) : type(Type),x(X),y(Y),w(W),aid(Aid){}; 
    bool operator < (const Query & A)const { 
        return x == A.x ? type < A.type : x < A.x; 
    }
} ;
Query query[maxw / 10 + 7];
Query tmp[maxw / 10 + 7]; 
int ans[maxn],maxy;  
namespace BIT {
#define lowbit(x) (x & (-x))
    int sum[maxw << 1]; 
    void add(int idx,int val) { 
    //puts("1");
        for(;idx <= maxy; idx += lowbit(idx)) sum[idx] += val; 
    } 
    int query(int idx) { 
        int ret = 0; 
        for(;idx;idx -= lowbit(idx)) ret += sum[idx]; 
        return ret;  
    } 
    void clear(int idx) { 
        for(;idx <= maxy;idx += lowbit(idx)) { 
            if(sum[idx]) sum[idx] = 0; 
            else break; 
        } 
    } 
} 
void cdq(int l,int r) { 
    if(r - l <= 1) return; 
    int mid = l + r >> 1; 
    cdq(l,mid);cdq(mid,r); 
    int p = l,q = mid,cnt = l; 
    for(;p < mid && q < r;) {
        if(query[p] < query[q]) {
            if(query[p].type == 1) 
                BIT::add(query[p].y,query[p].w); 
            tmp[cnt ++] = query[p ++]; 
        }
        else { 
            if(query[q].type == 2) ans[query[q].aid] += query[q].w * BIT::query(query[q].y); 
            tmp[cnt ++] = query[q ++];  
        } 
    } 
    while(p < mid) tmp[cnt ++] = query[p ++]; 
    while(q < r)  {
        if(query[q].type == 2) ans[query[q].aid] += query[q].w * BIT::query(query[q].y); 
            tmp[cnt ++] = query[q ++]; 
    } 
    for(int i = l;i < r;++ i) { 
        BIT::clear(tmp[i].y); 
        query[i] = tmp[i];  
    } 
} 
int qid = 0,aid = 0;
int main() { 
    int type = read(), n = read(); 
    maxy = n; 
    for(int x,y,x1,y1,val;;) { 
        type = read(); 
        if(type == 3) break;  
        if(type == 1) {x = read(),y = read(),val = read();query[qid ++] = Query(1,x,y,val,0);  } 
        if(type == 2) { 
            x = read(),y = read(),x1 = read(),y1 = read(); 
            query[qid ++] = Query(2,x - 1,y - 1,1,aid); 
            query[qid ++] = Query(2,x - 1,y1,-1,aid); 
            query[qid ++] = Query(2,x1,y - 1,-1,aid); 
            query[qid ++] = Query(2,x1,y1,1,aid); 
            aid ++; 
        } 
    } 
    cdq(0,qid); 
    for(int i = 0;i < aid;++ i) printf("%d
",ans[i]); 
    return 0; 
} 
点分治

模拟退火

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 100007;
double x[maxn],y[maxn],w[maxn]; 
int n;double ansx,ansy,nowx,nowy,Ans = 1.0 * 1e18;
double calc(double X,double Y) {
    double ret = 0; 
    for(int i = 1;i <= n;++ i) 
        ret += w[i] * sqrt((X - x[i]) * (X - x[i]) + (Y - y[i]) * (Y - y[i]));
    if(ret < Ans) Ans = ret,ansx = X,ansy = Y;
    return ret;
}
double Random() {return (double) rand() / RAND_MAX;} 
void SA(double T) {
    nowx = ansx,nowy = ansy;
    double tmpx ,tmpy;
    while(T > 0.001) {
        tmpx = nowx + T * (Random() * 2 - 1);
        tmpy = nowy + T * (Random() * 2 - 1); 
        double DE = calc(nowx,nowy) - calc(tmpx,tmpy); 
        if(DE > 0 || Random() <= exp(DE/T)) 
            nowx = tmpx,nowy = tmpy;
        T *= 0.98;
    } 
     
    for(int i = 1;i <= 1000;++ i) {
        tmpx = ansx + T * (Random() * 2 - 1) ; 
        tmpy = ansy + T * (Random() * 2 - 1) ; 
        calc(tmpx,tmpy); 
    } 
}
int main() {
    srand(19260817); 
    scanf("%d",&n);
    for(int i = 1;i <= n;++ i) scanf("%lf%lf%lf",x + i,y + i,w + i),
        ansx += x[i],ansy += y[i]; 
    ansx /= n;ansy /= n;  
    //printf("%lf %lf
",Ans,ansy);
    SA(40000001); 
    printf("%.3lf %.3lf",ansx,ansy); 
    return 0; 
}
模拟退火

图论相关

lca相关

链剖求lca

#include <cstdio>
#include <cstdlib>
#define maxm 200010
struct edge{int to,len,next;}E[maxm];
int cnt,last[maxm],fa[maxm],top[maxm],deep[maxm],siz[maxm],son[maxm],val[maxm];
void addedge(int a,int b,int len=0)
{
    E[++cnt]=(edge){b,len,last[a]},last[a]=cnt;
}
void dfs1(int x)
{
    deep[x]=deep[fa[x]]+1;siz[x]=1;
    for(int i=last[x];i;i=E[i].next)
    {
        int to=E[i].to;
        if(fa[x]!=to&&!fa[to]){
            val[to]=E[i].len;
            fa[to]=x;
            dfs1(to);
            siz[x]+=siz[to];
            if(siz[son[x]]<siz[to])son[x]=to;
        }
    }
}
void dfs2(int x)
{
    if(x==son[fa[x]])top[x]=top[fa[x]];
    else top[x]=x;
    for(int i=last[x];i;i=E[i].next)if(fa[E[i].to]==x)dfs2(E[i].to);
}
void init(int root){dfs1(root),dfs2(root);}
int query(int x,int y)
{
    for(;top[x]!=top[y];deep[top[x]]>deep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
    return deep[x]<deep[y]?x:y;
}
int n,m,x,y,v;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);addedge(x,y,v);addedge(y,x,v);
    }
    init(1);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        printf("%d
",query(x,y));
    }
    return 0 ;
}
链剖lca

倍增lca

//lca   倍增 
 2 /*倍增法
 3 
 4 首先如果两个点的深度如果不同,
 5 将深度较大的点跳到与深度较小的点一样的深度,
 6 再同时向上跳,首次相遇时即为最近公共祖先。
 7 */
 #include<cstdio>
 
 using namespace std;
 
 const int N=10015;
 
 vector<int>vec[N];
 int n,m,t,p,q;
 
 int dad[N][N],deep[N];
 
 void dfs(int x)
 {
     deep[x]=deep[dad[x][0]]+1;
     for(int i=0;dad[x][i];i++)
   {
         dad[x][i+1]=dad[dad[x][i]][i];//滚动赋值,如果存在节点x的第2^i的祖先那么节点x的第2^(i+1)个祖先=节点x的2^i的祖先再往前走2^i个祖先
     }
     for(int i=0;i<vec[x].size();i++)
     if(!deep[vec[x][i]])
     {
         dad[vec[x][i]][0]=x;
         dfs(vec[x][i]);
     }
 }
 
 int lca(int x,int y)
 {
     if(deep[x]>deep[y])swap(x,y);
     for(int i=20;i>=0;i--)
     {
         if(deep[dad[y][i]]>=deep[x])y=dad[y][i];
     }//自己跳 
     if(x==y)return x;
     
     for(int i=20;i>=0;i--)
     if(deep[dad[x][i]]!=deep[dad[y][i]])
     {
         x=dad[x][i];
         y=dad[y][i];
     }//一起跳 
     return dad[x][0]; 
 }
 
 int main()
 {
     scanf("%d%d%d",&n,&m,&t);//n个点,m条边,t个访问
     int x,y;
     
     for(int i=1;i<=m;i++)
     {
      scanf("%d%d",&x,&y);
         vec[x].push_back(y);
         vec[y].push_back(y);
     }
     dfs(1);
     while(t--)
     {
         scanf("%d%d",&p,&q);
         printf("%d
",lca(p,q));
     }
}
倍增lca

tarjan+缩点

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,m,topp;
#define N 100006
struct sta{
    int sz[100001];
    int top(){return sz[topp];}
    void push(int x){sz[++topp]=x;}
    void pop(){if(topp>0)topp--;}
}stack;

struct node{
    int v,next;
}edge[N*5];int head[N],num;
int dfn[N],low[N],color[N];bool vis[N];

void add_edge(int x,int y)
{
    edge[++num].v=y;edge[num].next=head[x];head[x]=num;
}
int cnt;
void tarjan(int x)
{
    dfn[x]=low[x]=++num;
    stack.push(x);
    vis[x]=1;
    for(int i=head[x];i;i=edge[i].next)
    {
        int v=edge[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(vis[v])low[x]=min(low[x],dfn[v]);    
    }
    if(dfn[x]==low[x])
    {
        ++cnt;
        int r;
        do{
            r=stack.top();
            color[r]=cnt;
            vis[r]=0;
            stack.pop();
        }while(r!=x);
    }
    return ;
}
int main()
{
    scanf("%d%d",&n,&m);
    int a,b;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);add_edge(a,b);
    }
    num=0;
    for(int i=1;i<=n;i++)
    if(!dfn[i])tarjan(i);
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=edge[j].next)
        {
            int v=edge[j].v;
            if(color[i]!=color[v])
            {
                vis[color[v]]=1;
            }
        }
    }
    int ans=0;
    for(int i=1;i<=cnt;i++)
        if(!vis[i]) ans++;
    printf("%d
",ans);
    return 0;
}
tarjan+缩点

树剖

#include<bits/stdc++.h>
using namespace std; 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' ||c > '9'){if(c == '-')f= -1; c = getchar();} 
    while(c <= '9' &&c >= '0')x = x * 10 + c- '0',c = getchar(); 
    return x * f; 
} 
#define int long long
const int maxn = 200007; 
int n,m,val[maxn]; 
struct node { 
    int u,v,next;
} edge[maxn << 1]; 
int head[maxn],num; 
inline void add_edge(int u,int v) { 
    edge[++ num].v = v; edge[num].next = head[u];head[u] = num ; 
} 
int fa[maxn],deep[maxn],siz[maxn],son[maxn]; 
void dfs1(int x) { 
    deep[x] = deep[fa[x]] + 1;siz[x] = 1;  
    for(int i = head[x];i ;i = edge[i].next) { 
        int v = edge[i].v; 
        if(deep[v]) continue; 
        fa[v] = x; dfs1(v); 
        siz[x] += siz[v]; 
        if(siz[v] > siz[son[x]] || !son[x]) son[x] = v; 
    } 
}    
int pos[maxn],_pos,sop[maxn],top[maxn]; 
void dfs2(int x,int topfa) { 
    top[x] = topfa;pos[x] = ++_pos;sop[_pos] = x; 
    if(!son[x]) return ;
    dfs2(son[x],topfa); 
    for(int i = head[x];i;i = edge[i].next) { 
        int v = edge[i].v; 
        if(v == son[x] || v == fa[x]) continue; 
        dfs2(v,v); 
    } 
} 
#define lc rt << 1 
#define rc rt << 1 | 1 
int sum[maxn << 2],tag[maxn << 2]; 
inline void update(int rt) {sum[rt] = sum[lc] + sum[rc]; } 
void build(int rt,int l,int r) { 
    if(l == r) { 
        sum[rt] = val[sop[l]];return ;  
    } 
    int mid = l + r >> 1; 
    build(lc,l,mid); build(rc,mid + 1,r); 
    return update(rt); 
} 
inline void pushdown(int rt,int l,int r) { 
    int mid = l + r >> 1; 
    tag[lc] += tag[rt];tag[rc] += tag[rt]; 
    sum[lc] += (mid - l + 1) * tag[rt]; 
    sum[rc] += (r - mid) * tag[rt]; 
    tag[rt] = 0; 
} 
int T_query(int rt,int l,int r,int tl,int tr ){ 
    if(l >= tl && r <= tr) return sum[rt]; 
    if(tag[rt] != 0) pushdown(rt,l,r); 
    int mid = l + r >> 1,Ret = 0 ; 
    if(tl <= mid) Ret += T_query(lc,l,mid,tl,tr);  
    if(tr > mid)  Ret += T_query(rc,mid + 1,r,tl,tr); 
    return Ret;  
} 
void T_modify(int rt,int l,int r,int tl,int tr,int a) { 
    if(l >= tl && r <= tr) { 
        sum[rt] += (r - l + 1) * a; 
        tag[rt] += a; return ; 
    } 
    if(tag[rt] != 0)pushdown(rt,l,r); 
    int mid = l + r >> 1; 
    if(tl <= mid) T_modify(lc,l,mid,tl,tr,a); 
    if(tr > mid)  T_modify(rc,mid + 1,r,tl,tr,a); 
    update(rt); 
} 
int Q(int x) { 
    int ret = 0 ;
    for(;top[x] != 1;x = fa[top[x]]) 
        ret += T_query(1,1,n,pos[top[x]],pos[x]); 
    ret += T_query(1,1,n,pos[top[x]],pos[x]); 
    return ret; 
} 
void M1(int x,int a) { T_modify(1,1,n,pos[x],pos[x],a);  }  
void M2(int x,int a) {  T_modify(1,1,n,pos[x],pos[x] + siz[x] - 1,a); }    
main() { 
    n = read(),m = read(); 
    for(int i = 1;i <= n;++ i) val[i] = read(); 
    for(int u,v,i = 1;i < n;++ i) { 
        u = read(); v = read(); 
        add_edge(u,v); add_edge(v,u); 
    } 
    dfs1(1);  
    dfs2(1,1); 
    build(1,1,n); 
    for(int type,x,a;m --;) { 
        type = read(); 
        if(type == 1) { 
            x = read(); a = read(); 
            M1(x,a); 
        } else if(type == 2) { 
            x = read(); a = read(); 
            M2(x,a);    
        } else { 
            x = read(); 
            printf("%lld
",Q(x)) ;  
        } 
    } 
    return 0; 
} 
树剖

割边

void tarjan(int u,int fa) {
    dfn[u] = low[u] = ++tn;
    for (int i=head[u]; i; i=e[i].nxt) {
        int v = e[i].to;
        if (!dfn[v]) {
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if (low[v] > dfn[u]) {
                printf("%d %d
",u,v);
            }
        }
        else if (dfn[v] < dfn[u] && v != fa) 
            low[u] = min(low[u],dfn[v]);
    }
}
割边

割点

void tarjan(int u,int fa) {
    low[u] = dfn[u] = ++tn;
    int cnt_son = 0;
    for (int i=head[u]; i; i=e[i].nxt) {
        int v = e[i].to;
        if (!dfn[v]) {
            cnt_son++;
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if (low[v] >= dfn[u]) 
                iscut[u] = true;
        }
        else if (dfn[v] < dfn[u] && v != fa) 
            low[u] = min(low[u],dfn[v]);
    }
    if (fa<0 && cnt_son==1) iscut[u] = false;
}
割点
边双连通分量
写法1
void tarjan(int u,int fa) {
    dfn[u] = low[u] = ++tn;
    st[++top] = u;
    vis[u] = true;
    for (int i=head[u]; i; i=e[i].nxt) {
        int v = e[i].to;
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if (vis[v] && v!=fa) 
            low[u] = min(low[u],dfn[v]);
    }
    if (dfn[u] == low[u]) {
        ++cnt;
        do {
            vis[st[top]] = false;
            bel[st[top]] = cnt;
            top--;
        } while (st[top+1] != u);
    }
}
边双联通分量写法1

写法2

void tarjan(int u,int fa) {
    dfn[u] = low[u] = ++tn;
    for (int i=head[u]; i; i=e[i].nxt) {
        int v = e[i].to;
        if (!dfn[v]) {
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
        }
        else if (dfn[v] < dfn[u] && v != fa) 
            low[u] = min(low[u],dfn[v]);
    }
}
边双联通分量

堆优化dijkstra

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define INF 0x3f3f3f3f
#define N 1020

int n,m;
int head[N];
int dis[N];

struct nnode{
    int v;int w,next;
}edge[N*N/2];
struct node{
    int v,dis;
    friend bool operator < (node a,node b){
        return a.dis>b.dis;
    }
}cur;
priority_queue<node>q;

int read() {
    int x=0,f=1;
    char c;
    while (c<'0' || c>'9') {if(c=='-')f = -1;c = getchar();}
    while (c>='0' && c<='9')x=x*10+c-'0',c=getchar();
    return x*f;
}

int num = 0;
void add_edge(int x,int y,int w)
{
    edge[num].v=y;
    edge[num].w=w;
    edge[num].next=head[x];
    head[x]=num++;
}
int pre_now[N];
int pre[N];
int Dijkstra(int p,int tp)
{
    //memset (head,-1,sizeof -1);
    memset (dis,0x3f,sizeof dis);
    dis[1] = 0;
    q.push(node{1,0});
    while(!q.empty())
    {
        cur = q.top();
        q.pop();
        if(dis[cur.v]<cur.dis)continue;
        int u = cur.v;
        for (int i = head[u];i != -1;i = edge[i].next)
        {
            int v = edge[i].v;
            if((v == p && u== tp) || (v==tp && p == u))continue;
            if(dis[v]>dis[u]+edge[i].w)
            {
                dis[v]=dis[u]+edge[i].w;
                pre_now[v]=u;
                q.push((node){v,dis[v]});
            }
        }
    }
    return dis[n];
}

int main() 
{
    n = read();
    m = read();
    for(int i=1;i<=n;i++)head[i]=-1;    
    for (int i = 1; i <= m; i++){
        int a,b,c;
        a = read(),b = read(),c = read();
        add_edge(a,b,c);add_edge(b,a,c);
    }
    int ans=Dijkstra(0,0);
    memcpy(pre,pre_now,sizeof(pre));
    int k=n;
    while(k)
    {
        int tmp = Dijkstra(pre[k],k);
        if(tmp!=INF)
        ans = max(ans,tmp);
        k = pre[k];
    }
    
    printf("%d
",ans);
    return 0;
}
Dijkstra

网络流相关

最大流

bool spfa() {
    memset(lev,-1,sizeof lev);
    memcpy(cur,head,sizeof head);
    queue<int>que;
    que.push(S);lev[S]=0;
    while(!que.empty()) {
        int u=que.front();que.pop();
        for(int i=head[u];i;i=edge[i].next) {
            int v=edge[i].v;
            if(edge[i].flow>0&&lev[v]<0) {
                lev[v]=lev[u]+1;que.push(v);
            }
        }
    }
    if(lev[T]!=-1)return true;
    else return false;
}   
int dfs(int now,int flow) {
    if(now==T)return flow;
    int rest=0,delta;
    for(int &i=cur[now];i;i=edge[i].next) {
        int v=edge[i].v;
        if(lev[v]==lev[now]+1&&edge[i].flow>0) {
            delta=dfs(v,min(flow-rest,edge[i].flow));
            if(delta) {
                edge[i].flow-=delta;
                edge[i^1].flow+=delta;
                rest+=delta;if(rest==flow)break;
            }
        }
    }
    if(rest==flow)lev[now]=-1;
    return rest;
}
int ans=0;
void dinic() {
    while(spfa())
         ans-=dfs(S,INF);
}
Dinic

最小费用最大流

#include<queue>
#include<cstdio>
#include<cstring> 
#include<algorithm>
using namespace std;
const int maxn = 4*50000;
inline int read()
{
    int x=0,f=1;char c= getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c-'0');c=getchar();}
    return f*x;
}
struct node{
    int u,v,cost,flow,next;
}edge[maxn];
int head[maxn],num=1,n,m,s,t;
int min_cost=0,max_flow=0;
int dis[maxn],pre[maxn];
bool vis[maxn];
inline void add_edge(int x,int y,int z,int c)
{    
    edge[++num].v=y;edge[num].u=x;edge[num].flow=z;edge[num].cost=c;edge[num].next=head[x];head[x]=num;
}
bool spfa()
{
    memset(dis,0x3f,sizeof dis);
    memset(vis,0,sizeof vis);
    vis[s]=1;
    dis[s]=0;
    queue<int>que;
    que.push(s);
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=head[u];i;i=edge[i].next)
        {
            int v=edge[i].v;
            if(dis[u]+edge[i].cost<dis[v]&&edge[i].flow>0)
            {
                dis[v]=edge[i].cost+dis[u];
                pre[v]=i;
                if(!vis[v])
                {
                    que.push(v);
                    vis[v]=1;
                }
            }
        }
        vis[u]=0;
    }
    if(dis[t]==0x3f3f3f3f)return 0;
    else return 1;
}
void work()
{
    int ma=0x3f3f3f3f;
    for(int i=t;i!=s;i=edge[pre[i]].u)
        ma=min(edge[pre[i]].flow,ma);
    for(int i=t;i!=s;i=edge[pre[i]].u)
    {
        edge[pre[i]].flow-=ma;
        edge[pre[i]^1].flow+=ma;
        min_cost+=(ma*edge[pre[i]].cost);
    }
    max_flow+=ma;
}
void miku()
{
    while(spfa())
        work();
}
int main()
{
    n=read(),m=read(),s=read(),t=read();
    int a,b,c,d;
    while(m--)
    {
        a=read(),b=read(),c=read(),d=read();
        add_edge(a,b,c,d);
        add_edge(b,a,0,-d);
    }
    miku();
    printf("%d %d
",max_flow,min_cost);
    return 0;
}
spfa费用流

DP相关

lcs

#include<map>
#include<cstdio>
#include<algorithm>
using namespace std;
map<int,int>mp;
inline int read()
{
    int x=0;char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar() ;
    return x;
}
int n,m,f[200010];
int ef_search(int l,int r,int x)
{
    while(l<r)
    {
        int mid=l+r>>1;
        if(x<=f[mid])r=mid;
        else l=mid+1;
    }
    return l;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        mp[read()]=i;
    int len=0;
    for(int pos,i=1;i<=m;i++)
    {
        pos=mp[read()];
        if(!pos)continue;
        if(pos>f[len])f[++len]=pos;
        else {
            f[ef_search(1,len,pos)]=pos;
        }
    }
    printf("%d
",len);
    return 0;
 }
lcs
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=505;
int n,m,a[maxn],b[maxn];
struct hehe {
    int num;
    vector<int>point;
} dp[maxn],tmp,ans;

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&m);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    for(int i=1;i<=n;i++) {
        tmp.num=0;
        tmp.point.clear();
        for(int j=1;j<=n;j++) {
            if (b[i]>a[j] && dp[j].num>tmp.num) tmp=dp[j];
            if (a[j]==b[i]) {
                dp[j]=tmp;
                dp[j].num=tmp.num+1;
                dp[j].point.push_back(a[j]);
            }
        }
    }
    for(int i=1;i<=n;i++)
    if (dp[i].num>ans.num) ans=dp[i];
    printf("%d
",ans.num);
    for (int k=0; k<ans.point.size(); k++)
        printf("%d ",ans.point[k]);
    return 0;
}
上升公共

上升

#include<cstdio>
#include<iostream>
using namespace std;
int ans[100000];
int a[100000];int len=1;
inline int mid_serch(int x)
{
    int l=0,r=len;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(ans[mid]<a[x])l=mid+1;
        else r=mid-1;
    }
    return l;
} 
int main()
{
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;++i)scanf("%d",a+i);
    ans[1]=a[1];
    for(int i=2;i<=m;++i)
    {
        if(a[i]>ans[len])
        ans[++len]=a[i];
        else {
            int tmp=mid_serch(i);
            ans[tmp]=a[i];
        }
    }
    printf("%d",len);
}
上升

多项式

#include<cmath> 
#include<cstdio>
#include<cstring> 
#include<algorithm> 

inline int read() { 
    int x = 0; 
    char c = getchar(); 
    while(c < '0' || c > '9') c = getchar(); 
    while(c <= '9' && c >= '0')x = x * 10 + c- '0',c = getchar(); 
    return x ; 
} 
#define pi acos(-1.0) 
struct Complex {
    double x,y; 
    Complex(double a = 0,double b = 0) : x(a),y(b)  {}; 
} ;
Complex operator + (Complex a,Complex b) { return Complex(a.x + b.x,a.y + b.y);} 
Complex operator - (Complex a,Complex b) { return Complex(a.x - b.x,a.y - b.y);} 
Complex operator * (Complex a,Complex b) { return Complex(a.x * b.x - a.y * b.y,a.x * b.y + a.y * b.x);} 

const int maxn = 1000007; 
int n;
Complex A[maxn],B[maxn],C[maxn];  
void fft(Complex *a,int n,int type) { 
    for(int i = 0,j = 0;i < n;++ i) { 
        if(i < j) std::swap(a[i],a[j]); 
        for(int k = n >> 1;(j ^= k) < k;k >>= 1);
    } 
    for(int m = 2;m <= n;m <<= 1) { 
        Complex w1 = Complex (cos(2 * pi / m),type * sin(2 * pi / m)); 
        for(int i = 0;i < n;i += m) { 
            Complex w = Complex(1,0); 
            for(int k = 0;k < (m >> 1);++ k) {
                Complex t = w * a[i + k + (m >> 1)],u = a[i + k]; 
                a[i + k] = u + t; 
                a[i + k + (m >> 1)] = u - t; 
                w = w  * w1; 
            } 
        } 
    } 
} 
Complex ans[maxn]; 
int main() { 
    n = read(); int lim = 0; 
    for(int tmp,i = 1;i <= n;++ i) { 
        tmp = read(); 
        A[tmp] = Complex(1,0); 
        B[tmp * 2] = Complex(1,0); 
        C[tmp * 3] = Complex(1,0); 
        lim = std::max(lim,tmp * 3); 
    } 
    for(n = 1;n <= lim;n <<= 1); 
    fft(A,n,1); 
        fft(B,n,1); 
    fft(C,n,1); 
    for(int i = 0;i < n;++ i) 
        ans[i] = A[i] + (A[i] * A[i] - B[i]) * Complex(1.0 / 2.0,0) + (A[i] * A[i] * A[i] - A[i] * B[i] * Complex(3.0,0) + Complex(2.0,0) * C[i]) * Complex(1.0 / 6.0,0); 
    fft(ans,n,-1); 
    for(int i = 0;i < n;++ i) { 
        int T = ans[i].x / n + 0.5; 
        if(T) printf("%d %d
",i,T); 
    }   
    return 0; 
}   
fft
/*
苟活者在淡红的血色中,会依稀看到微茫的希望
*/
 
#include<bits/stdc++.h>
using namespace std;
inline int read() {
    int   x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9'){if(c == '-')f = - 1; c =  getchar(); }
    while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar();
    return x * f;
}
const int maxn = 1000007;
const int P = 998244353,G = 3,Gi = 332748118;
#define LL long long
LL pre[maxn],now[maxn];
int n,m,limit = 1,k,prek,K,L,r[maxn];
inline LL fastpow(LL a, LL k) {
    LL base = 1;
    while(k) {
        if(k & 1) base = (base * a ) % P;
        a = (a * a) % P;
        k >>= 1;
    }
    return (base % P + P) % P;
}
inline void NTT(LL *A, int type) {
    for(int i = 0; i < limit; i++)
        if(i < r[i]) swap(A[i], A[r[i]]);
    for(int mid = 1; mid < limit; mid <<= 1) { 
        LL Wn = fastpow( type == 1 ? G : Gi , (P - 1) / (mid << 1));
        for(int j = 0; j < limit; j += (mid << 1)) {
            LL w = 1;
            for(int k = 0; k < mid; k++, w = (w * Wn) % P) {
                 int x = A[j + k], y = w * A[j + k + mid] % P;
                 A[j + k] = (x + y) % P,
                 A[j + k + mid] = (x - y + P) % P;
            }
        }
    }
}
LL inv[maxn];
void work(int k,int prek) {
    limit = 1;
    L = 0;
    for(int c = 1,i = 1;i <= k;++ i) now[i] = c = 1ll * c * (k - i + 1) % P * inv[i] % P;
    while(limit <= k + prek) limit <<= 1,L ++;
    for(int i = 0;i < limit;++ i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
    NTT(now,1);NTT(pre,1);
    for(int i = 0;i < limit;++ i) now[i] = (now[i] * pre[i]) % P;
    NTT(now,-1);
    LL inv = fastpow(limit, P - 2);
    for(int i = 0;i <= k + prek;++ i) now[i] = (now[i] * inv) % P;
} 
int t[maxn]; 
int main() {
    n = read(); m = read(),K = read();
    prek = read() ; 
    for(int i = 1;i <= prek;++ i) pre[i] = 1;
    inv[1] = 1; 
    for(int i = 2;i <= m;++ i) t[i - 1] = read(); 
    random_shuffle(t + 1,t + m); 
    for(int i = 2; i <= n; ++ i)
        inv[i]=1ll*(P-P/i)* inv[P % i] % P;
    for(int k = 0,i = 1;i < m;++ i) {
        k = t[i]; 
        work(k,prek);
        for(int i = 0;i <= k + prek;++ i) pre[i] = now[i],now[i] = r[i] = 0;
        prek = k + prek;
    }
    printf("%d
",pre[K]);
    return 0;
} 
ntt
原文地址:https://www.cnblogs.com/sssy/p/7358978.html