代码仓库

二次剩余

ll n,p,w;
int t;

inline ll ksm(ll a,ll b){
	ll res=1;
	while(b){
		if(b&1) res=(res*a)%p;
		a=(a*a)%p;
		b>>=1;
	}
	return (res%p+p)%p;
}

inline ll lrd(ll x){
	return ksm(x,(p-1)>>1);
}

struct rode{
	ll x,y;
	inline void intt(ll x_,ll y_){
		x=x_;y=y_;
	}
};

inline rode operator * (const rode &a,const rode &b){
	rode c;c.intt(((a.x*b.x)%p+a.y*b.y%p*w%p)%p,(a.x*b.y%p+a.y*b.x%p)%p);
	return c;
}

inline rode operator ^ (rode a,ll b){
	rode c;c.intt(1,0);
	while(b){
		if(b&1) c=c*a;
		a=a*a;
		b>>=1;
	}
	return c;
}

inline void solve(ll x){
	int if_=lrd(x);
	if(if_==p-1) printf("Hola!\n");
	else if(if_==0) printf("0\n");
	else{
		ll q=rand()%p;w=(((q*q)%p-n)%p+p)%p;
		while(lrd(w)<=1) q=rand()%p,w=(((q*q)%p-n)%p+p)%p;
		rode a;a.intt(q,1);
		a=a^((p+1)>>1);
		ll ans1=a.x,ans2=p-ans1;
		if(ans1>ans2) ans1^=ans2,ans2^=ans1,ans1^=ans2;
		printf("%lld %lld\n",ans1,ans2);
	}
}

int main(){
	srand(time(0));
	scanf("%d",&t);
	while(t--){
		scanf("%lld%lld",&n,&p);
		solve(n);
	}
	return 0;
}

李超树

#define f(i,x) (K[(i)]*(x)+B[(i)])
#define ls(k) k<<1
#define rs(k) k<<1|1
inline void Change(int k,int l,int r,int z,int y,int id){
    // if(id==243) printf("z=%d y=%d\n",z,y);
    // printf("k=%d l=%d r=%d z=%d y=%d id=%d v[k]=%d\n",k,l,r,z,y,id,v[k]);
    if(l==r){if(!v[k]||f(v[k],l)<f(id,l)) v[k]=id;return;}
    int mid=(l+r)>>1;
    if(z<=l&&r<=y){
        if(!v[k]) v[k]=id;
        if(f(v[k],mid)<f(id,mid)) swap(v[k],id);
        (f(v[k],l)<f(id,l))?Change(ls(k),l,mid,z,y,id):Change(rs(k),mid+1,r,z,y,id);
    }
    else{
        if(z<=mid) Change(ls(k),l,mid,z,y,id);if(y>mid) Change(rs(k),mid+1,r,z,y,id);
    }
}
inline int Ask(int k,int l,int r,int w){
    if(l==r) return v[k];int mid=(l+r)>>1;
    int nowid;if(w<=mid) nowid=Ask(ls(k),l,mid,w);else nowid=Ask(rs(k),mid+1,r,w);
    // printf("k=%d l=%d r=%d w=%d nowid=%d v[k]=%d\n",k,l,r,w,nowid,v[k]);
    return (f(v[k],w)<f(nowid,w))?nowid:v[k];
}

dinic 费用流

inline bool spfa(){
    mset(vis,0);q.push(s);vis[s]=1;mset(d,INF);d[s]=0;
    while(q.size()){
        int top=q.front();q.pop();now[top]=head[top];vis[top]=0;
        Next(top){
            int to=li[x].to,w=li[x].w,f=li[x].f;
            if(d[to]<=d[top]+w||!f) continue;
            d[to]=d[top]+w;if(!vis[to]) q.push(to),vis[to]=1;
        }
    }
    if(d[t]==INF) return 0;return 1;
}
inline int dinic(int k,int flow){
    if(k==t) return flow;vis[k]=1;int rest=flow,x;
    for(x=now[k];x;x=li[x].next){
        int to=li[x].to,w=li[x].w,f=li[x].f;
        if((vis[to]&&to!=t)||d[to]!=d[k]+w||!f) continue;int now=dinic(to,min(rest,f));if(!now) d[to]=INF;
        rest-=now;li[x].f-=now;li[x^1].f+=now;Ans+=w*now;
        if(!rest) break;
    }
    now[k]=x;return flow-rest;
}

  • 注意 dinic 函数中第三个判断条件不能省。
  • \(\text{d[t]}\) 的判断一定要放在最后。

原因:对于第一个,可能会有负环,就会陷入死循环。对于第二个,如果不放在最后,可能会导致最短路不优,而导致答案变大。

LCT

#define ls(k) ch[k][0]
#define rs(k) ch[k][1]
struct LCT{
    inline int Get(int k){return rs(fa[k])==k;}
    inline void PushUp(int k){
        val[k]=a[k]^val[ls(k)]^val[rs(k)];
    }
    inline void C(int k){
        swap(ls(k),rs(k));tag[k]^=1;
    }
    inline void PushDown(int k){
        if(tag[k]){
            C(ls(k));C(rs(k));tag[k]^=1;;
        }
    }
    inline bool Root(int k){
        int fat=fa[k];
        return ls(fat)!=k&&rs(fat)!=k;
    }
    inline void rotate(int k){
        int y=fa[k];int z=fa[y],x=Get(k);
        if(!Root(y)) ch[z][Get(y)]=k;
        ch[y][x]=ch[k][x^1];fa[ch[k][x^1]]=y;
        ch[k][x^1]=y;fa[y]=k;fa[k]=z;
        PushUp(y);PushUp(k);
    }
    inline void Update(int k){
        if(!Root(k)) Update(fa[k]);
        PushDown(k);
    }
    inline void Splay(int k){
        Update(k);
        for(int f=fa[k];!Root(k);rotate(k),f=fa[k]){
            if(!Root(f)) rotate(Get(k)==Get(f)?f:k);
        }
    }
    inline int Access(int k){
        int p;
        for(p=0;k;p=k,k=fa[k]){
            Splay(k);rs(k)=p;PushUp(k);
        }
        return p;
    }
    inline void MakeRoot(int k){
        k=Access(k);C(k);
    }
    inline void Split(int x,int y){
        MakeRoot(x);Access(y);Splay(y);
    }
    inline int Find(int k){
        Access(k);Splay(k);PushDown(k);
        while(ls(k)) k=ls(k),PushDown(k);
        Splay(k);return k;
    }
    inline void Cut(int a,int b){
        MakeRoot(a);
        if(Find(b)==a&&rs(a)==b&&ls(b)==0){
            rs(a)=fa[b]=0;PushUp(a);
        }
    }
    inline void Link(int a,int b){
        MakeRoot(a);if(Find(b)==a) return;Splay(a);fa[a]=b;
    }
    inline void Change(int k,int x){
        MakeRoot(k);a[k]=x;PushUp(k);
    }
    inline int Ask(int a,int b){
        Split(a,b);return val[b];
    }
}lct;

后缀自动机

struct node{
    int len,link,ch[26];
};

struct SAM{
    node p[N];
    int size,last;
    inline SAM(){
        p[0].len=0;p[0].link=-1;last=0;
    }
    inline void insert(int c){
        int cur=++size;f[size]++;
        p[cur].len=p[last].len+1;
        int now=last;
        while(now!=-1&&!p[now].ch[c]){
            p[now].ch[c]=cur;
            now=p[now].link;
        }
        if(now==-1) p[cur].link=0;
        else{
            int q=p[now].ch[c];
            if(p[now].len+1==p[q].len) p[cur].link=q;
            else{
                int clone=++size;
                p[clone]=p[q];p[clone].len=p[now].len+1;
                while(now!=-1&&p[now].ch[c]==q){
                    p[now].ch[c]=clone;now=p[now].link;
                }
                p[q].link=p[cur].link=clone;
            }
        }
        last=cur;
    }
};
SAM sam;

实现 Prufer 序列和无根树的双射 O(n) 算法

int n,m,d[N];

namespace Subtask1{

    int k=INF,fa[N],p[N];

    inline void Solve(){
        for(int i=1;i<=n-1;i++){
            int x;read(x);
            d[x]++;d[i]++;fa[i]=x;
        }
        for(int i=1,j=1;i<=n-2;i++,j++){
            while(d[j]!=1) j++;p[i]=fa[j];d[j]--;d[fa[j]]--;
            while(i<=n-2&&d[p[i]]==1&&p[i]<j){p[i+1]=fa[p[i]];d[p[i]]--;d[fa[p[i]]]--;i++;}
        }
        int ans=0;
        for(int i=1;i<=n-2;i++) ans=(ans^(i*p[i]));
        printf("%lld\n",ans);
    }
}

namespace Subtask2{

    int fa[N],p[N],d[N];

    inline void Solve(){
        for(int i=1;i<=n-2;i++) read(p[i]),d[p[i]]++;
        p[n-1]=n;
        for(int i=1;i<=n;i++) d[i]++;
        for(int i=1,j=1;i<=n-1;i++,j++){
            while(d[j]!=1) j++;fa[j]=p[i];d[j]--;d[p[i]]--;
            while(i<=n-1&&d[p[i]]==1&&p[i]<j){fa[p[i]]=p[i+1];d[p[i]]--;d[fa[p[i]]]--;i++;}
        }
        int ans=0;
        for(int i=1;i<=n-1;i++) ans=(ans^(i*fa[i]));
        printf("%lld\n",ans);
    }
}

拉格朗日插值

inline ll ksm(ll a,ll b,ll mod){
    ll res=1;
    while(b){
        if(b&1) (res*=a)%=mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}

inline ll inv(ll a){
    return ksm(a,mod-2,mod);
}

ll n,k,x[N],y[N],ans;

int main(){
    read(n);read(k);
    for(int i=1;i<=n;i++){
        read(x[i]);read(y[i]);
    }
    for(int i=1;i<=n;i++){
        ll fenzi=1,fenmu=1;
        for(int j=1;j<=n;j++){
            if(j==i) continue;
            fenmu*=(x[i]-x[j]);fenmu%=mod;
            fenzi*=(k-x[j]);fenzi%=mod;
        }
        ans+=y[i]*fenzi%mod*inv(fenmu)%mod;ans%=mod;
    }
    printf("%lld\n",(ans%mod+mod)%mod);
    return 0;
}
  • 需要把分母乘出来再求逆元,这样复杂度的瓶颈就不会是求逆元。

FWT 或卷积、和卷积、异或卷积

inline void FWT1(int *f,int n,int op){
    for(int mid=1;mid<=(n>>1);mid<<=1)
        for(int l=0;l<n;l+=(mid<<1))
            for(int i=l;i<=l+mid-1;i++){
                if(op==0){(f[i+mid]+=f[i])%=mod;}
                else{(f[i+mid]-=f[i])%=mod;}
            }
}

inline void FWT2(int *f,int n,int op){
    for(int mid=1;mid<=(n>>1);mid<<=1)
        for(int l=0;l<n;l+=(mid<<1))
            for(int i=l;i<=l+mid-1;i++){
                if(op==0){(f[i]+=f[i+mid])%=mod;}
                else (f[i]-=f[i+mid])%=mod;
            }
}

inline void FWT3(int *f,int n,int op){
    for(int mid=1;mid<=(n>>1);mid<<=1)
        for(int l=0;l<n;l+=(mid<<1))
            for(int i=l;i<=l+mid-1;i++){
                int a=f[i],b=f[i+mid];
                if(op==0){f[i]=(a+b)%mod;f[i+mid]=(a-b)%mod;}
                else{f[i]=1ll*((a+b)%mod)%mod*inv2%mod;f[i+mid]=1ll*((a-b)%mod)*inv2%mod;}
            }
}

dsu on tree

inline void dfs2(int k,bool op){
    for(int x=head[k];x;x=li[x].next){
        int to=li[x].to;
        if(to==fa[k]||to==son[k]) continue;
        dfs2(to,0);
    }
    if(son[k]){dfs2(son[k],1);vis[son[k]]=1;}
    Add(k);vis[son[k]]=0;
    ans[k]=sum;
    if(!op){Del(k);sum=0;maxx=0;}
}

set 维护凸包

inline void Insert(int id){
    P now=p[id];
    auto it=S.upper_bound(now);
    auto Right=it;auto Left=(--it);
    if(Cross(Subt((*Right),now),Subt((*Left),now))>=0) return;
    nowans-=GetDis((*Left),(*Right));
    while(it!=S.begin()){
        auto a=it;it--;
        if(Cross(Subt(now,(*a)),Subt((*it),(*a)))>=0){
            nowans=nowans-GetDis((*a),(*it));
            S.erase(a);
        }
        else break;
    }
    it=S.upper_bound(now);
    while((it)!=--S.end()){
        auto a=it;it++;
        if(Cross(Subt((*it),(*a)),Subt(now,(*a)))>=0){
            nowans=nowans-GetDis((*a),(*it));
            S.erase(a);
        }
        else break;
    }
    it=S.upper_bound(now);
    auto a=it,b=(--it);
    nowans+=GetDis((*b),now)+GetDis(now,(*a));
    S.insert(now);
}

求树上 k 级祖先

struct edge{
    int to,next;
    inline void Init(int to_,int ne_){
        to=to_;next=ne_;
    }
}li[N<<1];
int head[N],tail;

inline void Add(int from,int to){
    li[++tail].Init(to,head[from]);
    head[from]=tail;
}

int fa[N][21],Son[N],Dep[N],Deep[N],Top[N];
vector<int> u[N],d[N];

inline void dfs(int k,int fat){
    fa[k][0]=fat;for(int i=1;i<=20;i++) fa[k][i]=fa[fa[k][i-1]][i-1];
    Dep[k]=Dep[fat]+1;Deep[k]=Dep[k];
    for(int x=head[k];x;x=li[x].next){
        int to=li[x].to;
        if(to==fat) continue;
        dfs(to,k);Deep[k]=max(Deep[k],Deep[to]);
        if(Deep[Son[k]]<Deep[to]) Son[k]=to;
    }
}

inline void dfs2(int k,int t){
    Top[k]=t;
    if(k==t){
        int len=Deep[k]-Dep[t];
        d[k].push_back(k);int now=k;
        for(int i=1;i<=len;i++){
            now=Son[now];if(now==0) break;
            d[k].push_back(now);
        }
        u[k].push_back(k);now=k;
        for(int i=1;i<=len;i++){
            now=fa[now][0];if(now==0) break;
            u[k].push_back(now);
        }
    }
    if(Son[k]) dfs2(Son[k],t);
    for(int x=head[k];x;x=li[x].next){
        int to=li[x].to;
        if(to==fa[k][0]||to==Son[k]) continue;
        dfs2(to,to);
    }
}

uint s;
ll Ans;

inline uint get(uint x) {
	x ^= x << 13;
	x ^= x >> 17;
	x ^= x << 5;
	return s = x; 
}

int n,q,root,ans,lg2[N];

inline void Ask(){
    int x=((get(s)^ans)%n)+1;
    int k=(get(s)^ans)%Dep[x];
    // printf("x=%d k=%d\n",x,k);
    if(k==0){ans=x;return;}
    int nowx=fa[x][lg2[k]];int nowk=k-(1<<lg2[k]);
    // printf("nowx=%d nowk=%d\n",nowx,nowk);
    int t=Top[nowx],dep=Dep[nowx]-nowk;
    // printf("t=%d dep=%d\n",t,dep);
    // printf("Dep[t]=%d\n",Dep[t]);
    if(dep>Dep[t]) ans=d[t][dep-Dep[t]];
    else if(dep<=Dep[t]) ans=u[t][Dep[t]-dep];
}

KMP 从 0 开始

    nxt[0]=-1;
    for(int i=1,j=-1;i<len2;i++){
        while(j>-1&&s2[i]!=s2[j+1]) j=nxt[j];
        if(s2[i]==s2[j+1]) j++;
        nxt[i]=j;
    }
    for(int i=0,j=-1;i<len1;i++){
        while(j>-1&&(j==len1||s1[i]!=s2[j+1])) j=nxt[j];
        if(s1[i]==s2[j+1]) j++;f[i]=j;
    }

KMP 从 1 开始

    for(int i=2,j=0;i<=len2;i++){
        while(j>0&&s2[i]!=s2[j+1]) j=nxt[j];
        if(s2[i]==s2[j+1]) j++;
        nxt[i]=j;
    }
    for(int i=1,j=0;i<=len1;i++){
        while(j>0&&(j==len1||s1[i]!=s2[j+1])) j=nxt[j];
        if(s1[i]==s2[j+1]) j++;
        f[i]=j;
    }

EXKMP

int next[N],extend[N],lens,lent,ans;
char s[N],t[N];

inline void getnext(){
    next[0]=lent;int now=0;
    while(t[now]==t[1+now]&&now+1<lent) now++;
    next[1]=now;
    int p0=1;
    for(int i=2;i<lent;i++){
        if(i+next[i-p0]<next[p0]+p0) next[i]=next[i-p0];
        else{
            int now=next[p0]+p0-i;
            now=Max(now,0);
            while(t[now]==t[i+now]&&i+now<lent) now++;
            next[i]=now;
            p0=i;
        }
    }
}

inline void exkmp(){
    getnext();
    int now=0;
    while(s[now]==t[now]&&now<Min(lens,lent)) now++;
    extend[0]=now;
    int p0=0;
    for(int i=1;i<lens;i++){
        if(i+next[i-p0]<extend[p0]+p0) extend[i]=next[i-p0];
        else{
            int now=extend[p0]+p0-i;
            now=Max(now,0);
            while(t[now]==s[i+now]&&now<lent&&now+i<lens) now++;
            extend[i]=now;
            p0=i;
        }
    }
}

在代码中是从 \(0\) 开始的,所以 \(i\) 相当于 \(k+1\)\(next_{i-p_0}\) 相当于 \(l\)\(extend_{p_0}+p_0\) 相当于 \(p\)\(extend_{p_0}+p_0-i\) 为上图 \(s\) 字符串中 \(k+1\)\(p\) 的距离。

manacher

inline void Manacher(){
    mid=0;maxright=0;
    rep(i,1,n){
        if(i<maxright) Len[i]=min(Len[(mid<<1)-i],maxright-i);else Len[i]=1;
        while(i+Len[i]<=n&&i-Len[i]&&b[i+Len[i]]==b[i-Len[i]]) Len[i]++;
        if(i+Len[i]>maxright) maxright=i+Len[i],mid=i;
    }
}
//#a#a#a#

注意这里 len[(mid<<1)-i]\(j\) ,这里 len[mid]+mid-i\(i\) 到最右边的距离。
在实际实现中,我们让 \(maxright\) 作为最右边字符在往右的字符,这样比较好写一点。

后缀数组

inline void Sort(){
    for(int i=1;i<=n;i++) cnt[Rank[i]=s[i]]++;
    for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
    for(int i=n;i>=1;i--) sa[cnt[Rank[i]]--]=i;
    for(int w=1;;w<<=1,m=p){
        p=0;for(int i=n;i>n-w;i--) id[++p]=i;
        for(int i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w;
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=n;i++) cnt[px[i]=Rank[id[i]]]++;
        for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
        for(int i=n;i>=1;i--) sa[cnt[px[i]]--]=id[i];
        memcpy(LastRank,Rank,sizeof(Rank));p=0;
        for(int i=1;i<=n;i++) Rank[sa[i]]=Cmp(sa[i],sa[i-1],w)?p:++p;
        if(p==n) break;
    }
}

后缀数组求 height

inline void GetHeight(){
    for(int i=1,k=0;i<=n;i++){
        if(k) k--;
        while(s[i+k]==s[sa[rk[i-1]-1]+k]) k++;
        Height[rk[i]]=k;
    }
}

FFT 与 NTT(非转置原理实现)

注意到换完之后的位置实际上是原来位置的二进制翻转。而二进制翻转我们可以 \(O(n)\) 的去做这个东西。

注意到我们可以在转移上加以优化,这样就避免了所有数组的复制操作。

inline void Gettr(int n){
    for(int i=0;i<n;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?(n>>1):0);
}

inline void fft(cp *f,bool flag){
    for(int i=0;i<n;i++) if(i<tr[i]) swap(f[i],f[tr[i]]);
    for(int p=2;p<=n;p<<=1){
        int len=p>>1;
        cp tg(cos(2*pi/p),sin(2*pi/p));
        if(!flag) tg.y*=-1;
        for(int k=0;k<n;k+=p){
            cp buf(1,0);
            for(int l=k;l<k+len;l++){
                cp tt=buf*f[len+l];
                f[len+l]=f[l]-tt;
                f[l]=f[l]+tt;
                buf=buf*tg;
            }
        }
    }
}

inline void NTT(int *f,int len,int flag){
    for(int i=0;i<len;i++) if(i<tr[i]) swap(f[i],f[tr[i]]);
    for(int i=2;i<=len;i<<=1){
        int tg=ksm(g,(mod-1)/i,mod),l=i>>1;
        if(flag==-1) tg=ksm(tg,mod-2,mod);
        for(int j=0;j<len;j+=i){
            int buf=1;
            for(int k=j;k<j+l;k++){
                int tt=1ll*buf*f[k+l]%mod;
                f[k+l]=((f[k]-tt)%mod+mod)%mod;
                f[k]=(f[k]+tt)%mod;buf=1ll*buf*tg%mod;
            }
        }
    }
    if(flag==1) return;
    int inv=ksm(len,mod-2,mod);for(int i=0;i<len;i++) f[i]=1ll*f[i]*inv%mod;
}

多项式求逆

inline void GetInv(int len,const int *a,int *b){
    if(len==1){b[0]=ksm(a[0],mod-2,mod);return;}
    GetInv((len+1)>>1,a,b);int m=1;while(m<(len<<1)) m<<=1;Gettr(m);
    for(int i=0;i<len;i++) c[i]=a[i];for(int i=len;i<m;i++) c[i]=0;
    NTT(c,m,1);NTT(b,m,1);
    for(int i=0;i<m;i++) b[i]=1ll*(2-1ll*c[i]*b[i]%mod+mod)%mod*b[i]%mod;
    NTT(b,m,-1);for(int i=len;i<m;i++) b[i]=0;Clear(c,m);
}//c is not clear

多项式除法

inline void GetDivi(int lena,int lenb,const int *a,const int *b,int *f,int *h){
    int len=lena-lenb+1;int m=1;while(m<(len<<1)) m<<=1;
    for(int i=0;i<lena;i++) A[i]=a[i];for(int i=0;i<lenb;i++) B[i]=b[i];
    reverse(A,A+lena);reverse(B,B+lenb);
    for(int i=len;i<lena;i++) A[i]=0;for(int i=len;i<lenb;i++) B[i]=0;
    GetInv(len,B,d);Gettr(m);NTT(A,m,1);NTT(d,m,1);
    for(int i=0;i<m;i++) f[i]=1ll*A[i]*d[i]%mod;NTT(f,m,-1);
    for(int i=len;i<m;i++) f[i]=0;reverse(f,f+len);
    for(int i=0;i<lena;i++) A[i]=a[i];for(int i=0;i<lenb;i++) B[i]=b[i];
    m=1;while(m<(lenb+lena)) m<<=1;Gettr(m);
    NTT(A,m,1);NTT(B,m,1);for(int i=0;i<len;i++) c[i]=f[i];for(int i=len;i<m;i++) c[i]=0;
    NTT(c,m,1);for(int i=0;i<m;i++) h[i]=((A[i]-1ll*B[i]*c[i]%mod)%mod+mod)%mod;NTT(h,m,-1);
    for(int i=lenb;i<m;i++) h[i]=0;
}//A,B,c,d is not clear

多项式开根

inline void GetSqrt(int len,const int *a,int *b){
    if(len==1){b[0]=a[0];return;}
    GetSqrt((len+1)>>1,a,b);int m=1;while(m<(len<<1)) m<<=1;
    for(int i=0;i<len;i++) b[i]<<=1;
    for(int i=0;i<m;i++) d[i]=0;GetInv(len,b,d);
    for(int i=0;i<len;i++) b[i]>>=1;Gettr(m);
    for(int i=0;i<len;i++) c[i]=a[i];for(int i=len;i<m;i++) c[i]=0;
    NTT(c,m,1);NTT(c,m,1);NTT(b,m,1);
    for(int i=0;i<m;i++) b[i]=1ll*(1ll*b[i]*b[i]%mod+c[i])%mod*d[i]%mod;
    NTT(b,m,-1);
    for(int i=len;i<m;i++) b[i]=0;
}//c,d is not clear

多项式 exp

inline void GetExp(int len,const int *a,int *b){
    if(len==1){b[0]=1;return;}
    GetExp((len+1)>>1,a,b);GetLn(len,b,C);
    int m=1;while(m<(len<<1)) m<<=1;Gettr(m);
    for(int i=0;i<len;i++) A[i]=a[i];for(int i=len;i<m;i++) A[i]=0;
    NTT(b,m,1);NTT(C,m,1);NTT(A,m,1);
    for(int i=0;i<m;i++) b[i]=(1ll*b[i]*((A[i]-C[i])%mod)%mod+b[i])%mod;
    NTT(b,m,-1);for(int i=len;i<m;i++) b[i]=0;
    for(int i=0;i<m;i++) C[i]=0;Clear(A,m);Clear(B,m);Clear(c,m);Clear(d,m);Clear(C,m);
}//A,B,c,d,C is not clear

多项式取 ln

inline void GetLn(int len,const int *a,int *b){
    for(int i=1;i<len;i++) A[i-1]=1ll*a[i]*i%mod;
    for(int i=0;i<len;i++) B[i]=a[i];GetInv(len,B,d);
    int m=1;while(m<(len<<1)) m<<=1;NTT(A,m,1);NTT(d,m,1);
    for(int i=0;i<m;i++) b[i]=1ll*A[i]*d[i]%mod;NTT(b,m,-1);
    for(int i=len-1;i<m;i++) b[i]=0;
    for(int i=len-1;i>=1;i--) b[i]=1ll*b[i-1]*ksm(i,mod-2,mod)%mod;
    b[0]=0;Clear(A,m);Clear(B,m);Clear(c,m);Clear(d,m);
}//A,B,c,d, is not clear

Tarjan 求 scc

inline void Tarjan(int k){
    dfn[k]=low[k]=++tot;sta[++top]=k;ins[k]=1;
    for(int to:e[k]){
        if(!dfn[to]){Tarjan(to);low[k]=min(low[k],low[to]);}
        else if(ins[to]) low[k]=min(dfn[to],low[k]);
    }
    if(dfn[k]==low[k]){
        int z;ctot++;do{z=sta[top--];vdcc[ctot].pb(z);c[z]=ctot;ins[z]=0;}while(z!=k);
    }
}

线性基

struct LinearBasis{
    int p[N];
    inline void Insert(int x){
        dec(i,0,49) if((x>>i)&1){
            if(!p[i]){p[i]=x;return;}
            else x^=p[i];
        }
    }
    inline int Ask(){
        int ans=0;
        dec(i,0,49) if((ans^p[i])>ans) ans^=p[i];
        return ans;
    }
}lb;

左偏树

struct LeftHeap{
    inline int Merge(int a,int b){
        if(!a||!b) return a+b;if(p[b].v>p[a].v) swap(a,b);
        rs(a)=Merge(rs(a),b);if(p[rs(a)].dist>p[ls(a)].dist) swap(rs(a),ls(a));
        p[a].dist=p[rs(a)].dist+1;return a;
    }
    inline int Pop(int k){return Merge(ls(k),rs(k));}
}st;

自然数幂和拉格朗日插值部分

inline int Leg(int h){
    sum=1;rep(i,1,k+2) sum=1ll*sum*(h-x[i])%mod;
    rep(i,1,k+2) x[i]=sum*inv(h-x[i])%mod;
    int ans=0;
    rep(i,1,k+2){
        ans=(ans+y[i]*x[i]%mod*invjie[i-1]%mod*invjie[k+2-i]%mod*(((k+2-i)&1)?(mod-1):1)%mod)%mod;
    }
    return ans;
}

李超树

    struct Node{
        int ls,rs,mx,mi;
    }p[N];
    int tot;
    inline LCT(){tot=0;}
    inline void ChangeMin(int &k,int l,int r,int z,int y,int id){
        if(!k){k=++tot;assert(tot<=N-1);}
        if(l==r){if(!p[k].mi||F(p[k].mi,l)>F(id,l)) p[k].mi=id;return;}int mid=(l+r)>>1;
        if(z<=l&&r<=y){
            if(!p[k].mi) p[k].mi=id;
            if(F(p[k].mi,mid)>F(id,mid)) swap(p[k].mi,id);
            (F(id,l)<F(p[k].mi,l))?ChangeMin(ls(k),l,mid,z,y,id):ChangeMin(rs(k),mid+1,r,z,y,id);
            return;
        }
        if(z<=mid) ChangeMin(ls(k),l,mid,z,y,id);if(mid<y) ChangeMin(rs(k),mid+1,r,z,y,id);
    }
    inline void ChangeMax(int &k,int l,int r,int z,int y,int id){
        if(!k){k=++tot;}
        if(l==r){if(!p[k].mx||F(p[k].mx,l)<F(id,l)) p[k].mx=id;return;}int mid=(l+r)>>1;
        if(z<=l&&r<=y){
            if(!p[k].mx) p[k].mx=id;
            if(F(p[k].mx,mid)<F(id,mid)) swap(p[k].mx,id);
            (F(id,l)>F(p[k].mx,l))?ChangeMax(ls(k),l,mid,z,y,id):ChangeMax(rs(k),mid+1,r,z,y,id);
            return;
        }
        if(z<=mid) ChangeMax(ls(k),l,mid,z,y,id);if(mid<y) ChangeMax(rs(k),mid+1,r,z,y,id);
    }
    inline void Change(int &k,int l,int r,int z,int y,int id){
        ChangeMin(k,l,r,z,y,id);ChangeMax(k,l,r,z,y,id);
    }
    inline int AskMin(int k,int l,int r,int w){
        if(!k) return 0;if(l==r) return p[k].mi;
        int mid=(l+r)>>1;int id=-1;
        if(w<=mid) id=AskMin(ls(k),l,mid,w);else id=AskMin(rs(k),mid+1,r,w);
        if(id==0) return p[k].mi;
        return (F(id,w)<F(p[k].mi,w))?id:p[k].mi;
    }
    inline int AskMax(int k,int l,int r,int w){
        if(!k) return 0;if(l==r) return p[k].mx;
        int mid=(l+r)>>1;int id=-1;
        if(w<=mid) id=AskMax(ls(k),l,mid,w);else id=AskMax(rs(k),mid+1,r,w);
        if(id==0) return p[k].mx;
        return (F(id,w)>F(p[k].mx,w))?id:p[k].mx;
    }
    inline void Clear(){mset(p,0);rt=0;tot=0;}
posted @ 2023-07-13 21:06  NuclearReactor  阅读(48)  评论(0编辑  收藏  举报