template

Template for XCPC

图论

链式前向星

struct EDGE
{
    int to,w,next;
}edge[MAXN];
int head[MAXN],ptr=0;
void add_edge(int from,int to,int w)
{
    edge[++ptr].to=to;
    edge[ptr].w=w;
    edge[ptr].next=head[from];
    head[from]=ptr;
}

Dijkstra

void dijkstra(int s)
{
    typedef pair<int,int> PII;
    set<PII> minHeap;
    memset(d,0x3f,sizeof(d));
    minHeap.insert(make_pair(0,s));
    d[s]=0;
    while(!minHeap.empty())
    {
        int now=minHeap.begin()->second;
        int dis=minHeap.begin()->first;
        minHeap.erase(minHeap.begin());
        if(d[now]<dis) continue;
        for(int p=head[now]; p; p=edge[p].next)
        {
            int to=edge[p].to,w=edge[p].w;
            if(d[to]>(d[now]+w))
            {
                d[to]=d[now]+w;
                minHeap.insert(make_pair(d[to],to));
            }
        }
    }
   }

SPFA

bool mark[N];
bool SPFA(int s,int n)
{
    queue<int> que;
    int cnt[N];//访问次数
    memset(cnt,0,sizeof(cnt));
    memset(d,0x3f,sizeof(d));
    que.push(s);
    d[s]=0;
    while(!que.empty())
    {
        int t=que.front();
        mark[t]=0;
        cnt[t]++;
        if(cnt[t]>n)
            return 0;
        que.pop();
        for(int i=head[t]; i; i=edge[i].next)
        {
             int key=edge[i].to,len=edge[i].w;
            if(d[key]>(d[t]+len))
            {
                d[key]=d[t]+len;
                if(mark[key]==0)
                que.push(key),mark[key]=1;
            }
        }
    }
    return 1;
}

Floyd

for(int i=0; i<m; i++)
{
    int a,b,c;
    cin>>a>>b>>c;
    mapp[b][a]=mapp[a][b]=c;
}
for(int k=2; k<n; k++)
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            if(mapp[i][j]>mapp[i][k]+mapp[k][j])
                mapp[i][j]=mapp[i][k]+mapp[k][j];

拓扑排序

int in_deg[MAXN];
int ans_seq[MAXN],aptr;
int topo(int n)
{
    queue<int> que;
    for(int i=1;i<=n;i++)
        if(in_deg[i]==0)
            que.push(i);
    while(que.size())
    {
        int u=que.front();
        ans_seq[++aptr]=u;
        que.pop();
        for(int i=head[u];i;i=edge[i].next)
        {
            int to=edge[i].to;
            in_deg[to]--;
            if(in_deg[to]==0)
                que.push(to);
        }
    }
}

Tarjan

//强连通块
int belong[MAXN],scc;
int dfn[MAXN],low[MAXN];
int idx;
bool in_stk[MAXN];
stack<int> stk;
void tarjan(int now)
{
 dfn[now]=low[now]=++idx;
 stk.push(now);
 in_stk[now]=1;
 for(int p=head[now]; p; p=edge[p].next)
 {
     int to=edge[p].to;
     if(!dfn[to])
     {
         tarjan(to);
         low[now]=min(low[now],low[to]);
     }
     else if(in_stk[to])
         low[now]=min(low[now],dfn[to]);
 }
 if(dfn[now]==low[now])
 {
     int temp;
     scc++;
     do
     {
         temp=stk.top();
         belong[temp]=scc;
         in_stk[temp]=0;
         stk.pop();
     }
     while(temp!=now);
 }
}
//割点
int dfn[MAXN],low[MAXN],cut[MAXN];
int idx;
void tarjan(int now,int fa)
{
    dfn[now]=low[now]=++idx;
    int child=0;
    for(int p=head[now];p;p=edge[p].next)
    {
        int to=edge[p].to;
        if(!dfn[to])
        {
            tarjan(to,now);
            low[now]=min(low[now],low[to]);
            if(low[to]>=dfn[now]&&now!=fa)
                cut[now]=1;
            if(now==fa)
                child++;
        }
            low[now]=min(low[now],dfn[to]);
    }
    if(child>=2&&now==fa)
        cut[now]=1;
}

2-SAT

vector<int> ans;
bool SAT()
{
    for(int i=2; i<=2*k+1; i++)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=k;i++)
    {
        if(belong[i*2]==belong[i*2+1])
            return false;
        ans.push_back(belong[i*2]<belong[i*2+1]);
    }
    return true;
}

欧拉路 无向图

vector<int> ans;
int vis[MAXN];
void dfs(int now)
{
    for(int p=head[now]; p; p=edge[p].next)
        if(!vis[p])
        {
            vis[p]=vis[p^1]=1;
            dfs(edge[p].to);
        }
    ans.push_back(now);
}

LCA 倍增

int dep[MAXN],f[MAXN][20];
void dfs(int now,int fa)
{
 for(int p=head[now]; p; p=edge[p].next)
    {
        int to=edge[p].to;
        if(to==fa) continue;
        dep[to]=dep[now]+1;//计算深度
        f[to][0]=now;dfs(to,now);
    }
   }
   void dp()
   {
    //预处理 f[u][i] u结点往上走2^i次
 for(int i=1; (1<<i)<=n; i++)
     for(int u=1; u<=n; u++)
         f[u][i]=f[f[u][i-1]][i-1];//u结点往上走2^i次等于网上走两个2^(i-1)
   }
   int lca(int x,int y)
   {
    int p,t;
 if(dep[x]<dep[y])
     swap(x,y);//保证x比y大
 for(p=0; (1<<p)<=dep[x]; p++);//算出dp最多往上走2的多少次
    for(t=--p; t>=0; t--)//从x走到y同一层
        if(dep[x]-(1<<t)>=dep[y])//不超过的话就往上走
            x=f[x][t];
    if(x==y)
        return x;
    for(t=p; t>=0; t--)//x和y一起走 不相等就往上走
        if(f[x][t]!=f[y][t])
            x=f[x][t],y=f[y][t];
    return f[x][0];
   }

Kruskal

bool cmp(EDGE a,EDGE b)
{
    return a.w<b.w;
}
int kruskal()
{
    sort(edge,edge+m,cmp);
    dsu_init();
    int ans=0;
    for(int i=0; i<m; i++)
        if(!is_same(edge[i].u,edge[i].v))
            ans+=edge[i].w,dsu_merge(edge[i].u,edge[i].v);
    return ans;
}

树的重心

int siz[MAXN],w[MAXN],minn=INT_MAX,ans=INT_MAX,n;
void dfs(int now,int fa)
{
    siz[now]=1,w[now]=0;
    for(int p=head[now];p;p=edge[p].next)
    {
        int to=edge[p].to;
        if(to==fa)continue;
        dfs(to,now);
        w[now]=max(w[now],siz[to]);
    }
    w[now]=max(w[now],n-siz[now]);
    siz[fa]+=siz[now];
    if(w[now]<minn)
        ans=now,minn=w[now];
}

树链剖分 LCA

int f[MAXN],dep[MAXN],son[MAXN],siz[MAXN];
void dfs1(int now,int fa)
{
     f[now]=fa;
     siz[now]=1;
     dep[now]=dep[fa]+1;
     int maxn=0;
     for(int p=head[now];p;p=edge[p].next)
     {
          int to=edge[p].to;
          if(to==fa)continue;
          dfs1(to,now);
          siz[now]+=siz[to];
          if(maxn<siz[to])
               maxn=siz[to],son[now]=to;
     }
}
int tim,dfn[MAXN],top[MAXN],w[MAXN],val[MAXN];
void dfs2(int now,int t)
{
     dfn[now]=++tim;
     top[now]=t;
     w[tim]=val[now];
     if(!son[now])return;
     dfs2(son[now],t);
     for(int p=head[now];p;p=edge[p].next)
     {
          int to=edge[p].to;
          if(to==f[now]||to==son[now])continue;
          dfs2(to,to);
     }
}
int lca(int x,int y)
{
     while(top[x]!=top[y])
     {
          if(dep[top[x]]<dep[top[y]]) swap(x,y);
          //modify(dfn[top[x]],dfn[x])
          x=f[top[x]];
     }
     if(dep[x]>dep[y]) swap(x,y);
     //modify(dfn[x],dfn[y])
     return x;
}

树上启发式合并 CF600E

int f[MAXN],dep[MAXN],son[MAXN],siz[MAXN];
void dfs1(int now,int fa)
{
     f[now]=fa;
     siz[now]=2;
     dep[now]=dep[fa]+1;
     int maxn=0;
     for(int p=head[now];p;p=edge[p].next)
     {
          int to=edge[p].to;
          if(to==fa)continue;
          dfs1(to,now);
          siz[now]+=siz[to];
          if(maxn<siz[to])
               maxn=siz[to],son[now]=to;
     }
}
int cnt[MAXN],val[MAXN],maxn,flag,v,sum;
void cal(int now,int fa,int v)
{
    cnt[val[now]]+=v;
    if(cnt[val[now]]>maxn)
        maxn=cnt[val[now]],sum=val[now];
    else if(cnt[val[now]]==maxn)
        sum+=val[now];
    for(int p=head[now];p;p=edge[p].next)
    {
        int to=edge[p].to;
        if(to==fa||to==flag)continue;
        cal(to,now,v);
    }
}
int ans[MAXN];
void dfs2(int now,int fa,bool keep)
{
    for(int p=head[now];p;p=edge[p].next)
    {
        int to=edge[p].to;
        if(to==fa||to==son[now])continue;
        dfs2(to,now,0);
    }
    if(son[now])
    {
        dfs2(son[now],now,1);
        flag=son[now];
    }
    cal(now,fa,1);
    flag=0;
    ans[now]=sum;
    if(keep) return;
    cal(now,fa,-1);
    sum=maxn=0;
}

Dinic

int lev[N],cur[N];
int n,m,s,t;
void bfs()
{
    memset(lev,0,sizeof(lev));
    queue<int> que;
    lev[s]=1;
    que.push(s);
    while(que.size())
    {
        int now=que.front();
        que.pop();
        for(int p=head[now];p;p=edge[p].next)
            if(edge[p].cap>0&&lev[edge[p].to]==0)
            {
                lev[edge[p].to]=lev[now]+1,que.push(edge[p].to);
                if(edge[p].to==t)
                    return;
            }
    }
}
long long dfs(int from,long long f)
{
    if(from==t)
        return f;
    long long ret=0;
    for(int p=cur[from];p&&f;p=edge[p].next)
    {
        cur[from]=p;
        if(lev[edge[p].to]>lev[from]&&edge[p].cap>0)
        {
            long long d=dfs(edge[p].to,min(f,edge[p].cap));
            if(d>0)
            {
                edge[p].cap-=d;
                edge[p^1].cap+=d;
                ret+=d;
                f-=d;
            }
            else
                lev[edge[p].to]=0;
        }
    }
    return ret;
}
long long dinic()
{
    long long flow=0;
    for(;;)
    {
        bfs();
        if(lev[t]==0)
            return flow;
        memcpy(cur,head,sizeof(head));
        flow+=dfs(s,inf);
    }
}

MCMF

int n,m,s,t,ptr=1;
int pre[MAXN];
int d[MAXN];
bool mark[MAXN];
bool SPFA()
{
    queue<int> que;
    memset(d,0x3f,sizeof(d));
    que.push(s);
    d[s]=0;
    while(!que.empty())
    {
        int now=que.front();
        mark[now]=0;
        que.pop();
        for(int i=head[now]; i; i=edge[i].next)
        {
             int to=edge[i].to,len=edge[i].f;
            if(d[to]>(d[now]+len)&&edge[i].cap)
            {
                d[to]=d[now]+len;
                pre[to]=i;
                if(mark[to]==0)
                que.push(to),mark[to]=1;
            }
        }
    }
    if(d[t]==inf)
        return 0;
    return 1;
}
void MCMF(int &maxFlow,int &minCost)
{
    int sumflow=0;
    int minflow,mincost=0;
    while(SPFA())
    {
        minflow=inf;
        for(int i=pre[t];i;i=pre[edge[i^1].to])
            if(edge[i].cap<minflow)
                minflow=edge[i].cap;
        sumflow+=minflow;
        for(int i=pre[t];i;i=pre[edge[i^1].to])
        {
            edge[i].cap-=minflow;
            edge[i^1].cap+=minflow;
        }
        mincost+=d[t]*minflow;
    }
    maxFlow=sumflow;
    minCost=mincost;
}

Hungarian

int partner[MAXN];
bool vis[MAXN];
bool match(int u)
{
    for(int p=head[u];p;p=edge[p].next)
    {
        int to=edge[p].to;
        if(!vis[to])
        {
            vis[to]=1;
            if(partner[to]==0||match(partner[to]))
            {
                partner[to]=u;
                vis[to]=0;
                return 1;
            }
        }
    }
 return 0;
}
int Hungarian()
   {
    int cnt=0;
    for(int i=1;i<=M;i++)
        if(match(i))
            cnt++;
    return cnt;
   }

数据结构

ST表

int log2n[MAXN];
void log_ini()
{
    log2n[1]=0;
    log2n[2]=1;
    for(int i=3;i<MAXN;i++)
        log2n[i]=log2n[i>>1]+1;
}
int st[MAXN][20];
void st_ini(int n)
{
    for(int j=1;j<log2n[n]+1;j++)
        for(int i=0;i+(1<<j)-1<n;i++)
            st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int query(int l,int r)
{
    int p=log2n[r-l+1];
    return max(st[l][p],st[r-(1<<p)+1][p]);
}

树状数组(单点修改区间查询)

int bit[MAXN];
int lowbit(int x)
{
    return x & -x;
}
void add(int x,int v)
{
    for(;x<=MAXN;x+=lowbit(x))
        bit[x]+=v;
}
int query(int x) //0~x前缀和
{
    int res=0;
    for(;x;x-=lowbit(x))
        res+=bit[x];
    return res;
}

线段树(lazy)

struct node
{
    int l,r,v,col;
}sgt[MAXN
void iniSgt(int p,int l,int r)
{
    sgt[p].l=l;
    sgt[p].r=r;
    sgt[p].v=0;
    if(l==r)
        return;
    int mid=(l+r)/2;
    iniSgt(p*2,l,mid);
    iniSgt(p*2+1,mid+1,r);
}
void down(int p)
{
 if(sgt[p].col)
    {
        int l=sgt[p].l,r=sgt[p].r;
        int mid=(l+r)/2;
        sgt[p*2].v=sgt[p].col*(mid-l+1);
        sgt[p*2+1].v=sgt[p].col*(r-mid);
        sgt[p*2].col=sgt[p*2+1].col=sgt[p].col;
        sgt[p].col=0;
    }
   }
void modify(int p,int L,int R,int v)
{
 int l=sgt[p].l,r=sgt[p].r;
    if(l>=L&&r<=R)
    {
        sgt[p].col=v;
        sgt[p].v=(r-l+1)*v;
        return;
    }
    down(p);
    int mid=(l+r)/2;
    if(L<=mid)
        modify(p*2,L,R,v);
    if(R>=mid+1)
        modify(p*2+1,L,R,v);
    sgt[p].v=sgt[p*2].v+sgt[p*2+1].v;//用两个儿子更新爸爸
   }
int query(int p,int x,int y)
{
 int l=sgt[p].l,r=sgt[p].r;
    if(x<=l&&y>=r)
        return sgt[p].v;
    down(p);
    int mid=(l+r)/2,res=0;
    if(x<=mid)
        res+=query(p*2,x,y);
    if(y>mid)
        res+=query(p*2+1,x,y);
    return res;//用两个儿子更新爸爸
   }

DSU

int dsu[MAXN];
void init()
{
    for(int i=0;i<MAXN;i++)
        dsu[i]=i;
}
void fnd(int x)
{
    if(dsu[x]==x) return x;
    return dsu[x]=fnd(dsu[x]);
}
void merg(int x,int y)
{
    dsu[fnd(x)]=fnd(y);
}

主席树

struct node
{
    int ls,rs,v;
}st[MAXN];int ptr;
void iniSt(int &p,int l,int r)
{
    p=++ptr;
    if(l==r) return;
    int mid=(l+r)/2;
    iniSt(st[p].ls,l,mid);
    iniSt(st[p].rs,mid+1,r);
}
int modify(int p,int l,int r,int x,int v)
{
    int np=++ptr;
    st[np]=st[p];
    if(l==r)
    {
        st[np].v+=v;
        return np;
    }
    int mid=(l+r)/2;
    if(x<=mid)
        st[np].ls=modify(st[np].ls,l,mid,x,v);
    else
        st[np].rs=modify(st[np].rs,mid+1,r,x,v);
    st[np].v=st[st[np].ls].v+st[st[np].rs].v;//用两个儿子更新爸爸
    return np;
}
int rt[MAXN];
int ask(int p1,int p2,int l,int r,int c)
{
    if(l==r)return l;
    int mid=(l+r)/2;
    if(st[st[p2].ls].v-st[st[p1].ls].v>=c)
        return ask(st[p1].ls,st[p2].ls,l,mid,c);
    else
        return ask(st[p1].rs,st[p2].rs,mid+1,r,c-(st[st[p2].ls].vst[st[p1].ls].v));
}

字典树

int *ch[MAXN],cnt[MAXN],tot;
void update(string s)
{
    int ptr=0;
    for(int i=0;i<s.size();i++)
    {
        if(ch[ptr]==NULL)
        {
            ch[ptr]=new int[MAXC];
            memset(ch[ptr],0,sizeof(int)*MAXC);
        }
        int *nextNode=&ch[ptr][s[i]-'a'];
        if(*nextNode==0)
            *nextNode=++tot;
        ptr=*nextNode;
    }
    cnt[ptr]++;
}
int query(string s)
{
    int ptr=0;
    for(int i=0;i<s.size();i++)
    {
        if(ch[ptr]==NULL||ch[ptr][s[i]-'a']==0)
            return 0;
        ptr=ch[ptr][s[i]-'a'];
    }
    return cnt[ptr];
}

字符串

KMP

int next[N];
void getNext(string s)
{
    int j=0,k=-1;
    next[j]=k;
    while(j<s.size())
        if(k==-1||s[j]==s[k])
            next[++j]=++k;
        else
            k=next[k];
}
void kmp(string s,string str)
{
    int j=0,k=0,res=0;
    for(;j!=str.size();j++)
    {
        while(k!=-1&&s[k]!=str[j])
            k=next[k];
        k++;
        if(k==s.size())
            cout<<j-s.size()+1<<' ';
    }
}

EX-KMP

int next[N];
int extend[N];
void getNext(string s)
{
    int m=s.size();
    int a = 0, p = 0;
    next[0] = m;
    for (int i=1; i<m; i++)
    {
        if (i+next[i-a]>=p)
        {
            if(i>=p)
                p=i;
            while(p<m&&s[p]==s[p-i])
                p++;
            next[i]=p-i;
            a=i;
        }
        else
            next[i]=next[i-a];
    }
}
void getExtend(string str,string s)
{
    int n=str.size(),m=s.size();
    int a = 0, p = 0;
    getNext(s);
    for(int i=0; i<n; i++)
    {
        if(i+next[i-a]>=p)
        {
            if(i>=p)
                p=i;
            while(p<n&&p-i<m&&str[p]==s[p-i])
                p++;
            extend[i]=p-i;
            a=i;
        }
        else
            extend[i]=next[i-a];
    }
}

AC自动机

int ch[MAXN][MAXC],cnt[MAXN],tot,mark[MAXN],app[MAXN];
int next[MAXN],ptr,head[MAXN];
struct edge
{
    int to,next;
}edge[MAXN];
void update(string s,int m)
{
    int ptr=0;
    for(int i=0; i<s.size(); i++)
    {
        int *nextNode=&ch[ptr][s[i]-'a'];
        if(*nextNode==0)
            *nextNode=++tot;
        ptr=*nextNode;
    }
    cnt[ptr]++;
    mark[m]=ptr;
}
void add_edge(int u,int v)
{
    edge[ptr].to=v;
    edge[ptr].next=head[u];
    head[u]=ptr++;
}
int getNext()
{
    queue<int> que;
    for(int i=0; i<MAXC; i++)
    {
        if(ch[0][i]>0)
        {
            next[ch[0][i]]=0;
            que.push(ch[0][i]);
        }
    }
    while(que.size())
    {
        int now=que.front();
        que.pop();
        for(int i=0; i<MAXC; i++)
            if(ch[now][i]>0)
            {
                next[ch[now][i]]=ch[next[now]][i];
                que.push(ch[now][i]);
            }
            else
                ch[now][i]=ch[next[now]][i];
    }
    for(int i=1;i<=tot;i++)
        add_edge(next[i],i);
}
int query(string s)
{
    int now=0,ans=0;
    for(int i=0; i<s.size(); i++)
    {
        now=ch[now][s[i]-'a'];
        app[now]++;
    }
    return ans;
}
void dfs(int now)
{
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        dfs(edge[i].to);
        app[now]+=app[edge[i].to];
    }
}

数学

快速幂

int qpow(int a, int n){
    int ans = 1;
    while(n){
        if(n&1)
            ans *= a;
        a *= a;   
        n >>= 1;   
    }
    return ans;
}

欧拉定理、费马小定理

当a与n互质
a^φ(n)%n == 1
a^(p-1)%p == 1

除法取模

(b/a)%m   ==   b*a^(m-2)%m

线性筛

int vis[N], prim[N];
int pn = 0;
void table(){
    for(int i = 2;i < N;i++){
        if(!vis[i]) prim[pn++] = i;
        for(int j = 0;j < pn && 1LL*i*prim[j] < N;j++){
            vis[i*prim[j]] = 1;
            if(i % prim[j] == 0) break;
        }
    }
}

欧拉函数

int euler(int n)
{
    if(n==1)return 1;
    int res=n;
    for(int i=0,p=prim[i]; p*p<=n; i++,p=prim[i])
        if(n%p==0)
        {
            res=res/p*(p-1);
            while(n%p==0)n/=p;
        }
    if(n>1)res=res/n*(n-1);
    return res;
}

筛法求欧拉函数

int vis[N], prim[N];
int phi[N];
int pn = 0;
void table()
{
    phi[1]=1;
    for(int i = 2; i < N; i++)
    {
        if(!vis[i])
        {
            prim[pn++] = i;
            phi[i]=i-1;
        }
        for(int j = 0; j < pn && 1LL*i*prim[j] < N; j++)
        {
            vis[i*prim[j]] = 1;
            if(i % prim[j] == 0)
            {
                phi[i*prim[j]]=phi[i]*prim[j];
                break;
            }
            phi[i*prim[j]]=phi[i]*(prim[j]-1);
        }
    }
}

矩阵

struct mat
{
    int m[N+1][N+1];
    mat(){memset(m,0,sizeof(m));}
    mat(int n){mat();for(int i=1;i<=N;i++)m[i][i]=n;}
    mat operator *(const mat& b)
    {
        mat ret;
        for(int i=1;i<=N;i++)
            for(int k=1;k<=N;k++)
                for(int j=1;j<=N;j++)
                    ret.m[i][j]+=m[i][k]*b.m[k][j],ret.m[i][j]%=MOD;
        return ret;
    }
    mat operator +(const mat& b)
    {
        mat ret;
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                ret.m[i][j]=(m[i][j]+b.m[i][j])%MOD;
        return ret;
    }
};

扩展欧几里得

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

龟速乘

int lmul(int x,int y,const int &mod)
{
    int ans=0;
    while(y)
    {
        if(y&1)ans=(ans+x)%mod;
        x=(x+x)%mod;
        y>>=1;
    }
    return ans;
}

扩展中国剩余定理

int exCRT(int n,int *A,int *B)
{
    int x,y,ans=A[1],M=B[1],bg;
    for(int i=2; i<=n; i++)
    {
        int a=M,b=B[i],c=(A[i]-ans%b+b)%b;
        int gcd=exgcd(M,b,x,y);
        bg=b/gcd;
        if(c%gcd!=0) return -1;
        x=lmul(x,c/gcd,bg);
        ans+=x*M;
        M*=bg;
        ans=(ans%M+M)%M;
    }
    return ans;
}

高斯消元

// a[N][N]是增广矩阵
int gauss(int n)
{
    const double eps=1e-8;
    int c, r; // 列、行
    for (c = 0, r = 0; c < n; c ++ )
    {
        int t = r;
        for (int i = r; i < n; i ++ )   // 找到绝对值最大的行
            if (fabs(a[i][c]) > fabs(a[t][c]))
                t = i;
        if (fabs(a[t][c]) < eps) continue;// 该列元为自由元
        for (int i = c; i <= n; i ++ ) swap(a[t][i], a[r][i]);      // 将绝对值最大的行换到最顶端
        for (int i = n; i >= c; i -- ) a[r][i] /= a[r][c];      // 将当前上的首位变成1
        for (int i = r + 1; i < n; i ++ )       // 用当前行将下面所有的列消成0
            if (fabs(a[i][c]) > eps)
                for (int j = n; j >= c; j -- )
                    a[i][j] -= a[r][j] * a[i][c];
        r ++ ;
    }
    if (r < n) //r 不自由元数量
    {
        for (int i = r; i < n; i ++ )
            if (fabs(a[i][n]) > eps)
                return -1; // 无解
        return n-r; // 有无穷多组解 返回自由元个数
    }
    for (int i = n - 1; i >= 0; i -- )
        for (int j = i + 1; j < n; j ++ )
            a[i][n] -= a[i][j] * a[j][n];
    return 0; // 有唯一解
}

卢卡斯定理

int C(int a, int b)     // 通过定理求组合数C(a, b)
{
    int res = 1;
    for (int i = 1, j = a; i <= b; i ++, j -- )
    {
        res = (LL)res * j % p;
        res = (LL)res * qpow(i, p - 2) % p;
    }
    return res;
}
int lucas(int a, int b)
{
    if (a < p && b < p) return C(a, b);
    return C(a % p, b % p) * lucas(a / p, b / p) % p;
}

快速傅里叶变换

const int N=1050000;
const double PI=acos(-1.0);
struct CP{
    CP (double xx=0,double yy=0){x=xx,y=yy;}
    double x=0,y=0;
    CP operator + (CP const &B) const
    {return CP(x+B.x,y+B.y);}
    CP operator - (CP const &B) const
    {return CP(x-B.x,y-B.y);}
    CP operator * (CP const &B) const
    {return CP(x*B.x-y*B.y,x*B.y+y*B.x);}
}f[N<<1],p[N<<1];
//f[i].x,p[i].x分别是多项式的系数
int tr[N<<1];
void fft(int n,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;//p次单位根
        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;
            }
        }
    }
}
int FFT(int n,int m)
{
    for(m+=n,n=1;n<=m;)n<<=1;//把长度补齐
    for(int i=0;i<=n-1;i++){//蝴蝶变换
        tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
    }
    fft(n,f,1);fft(n,p,1);
    for(int i=0;i<=n-1;i++)f[i]=f[i]*p[i];
    fft(n,f,0);
    for(int i=0;i<=m;i++)f[i].x = (int)(f[i].x/n+0.49);
    return m;
}

杂项

二进制枚举子集

for (int i = s; i; i = (i - 1) & s)

快读快写

inline void read(__int128 &x)
{
   	int f = 1;
   	x = 0;
   	char ch = getchar();
   	while(ch < '0' || ch > '9')
   	{
   		if(ch == '-')
   			f *= -1;
   		ch = getchar();
   	}
   	while(ch >= '0' && ch <= '9')
   	{
   		x = x*10 + ch-'0';
   		ch = getchar();
	}
	x *= f;
}
   inline void print(__int128 x)
   {
   	if(x < 0)
   	{
   		putchar('-');
   		x = -x;
   	}
   	if(x > 9)
   		print(x/10);
   	putchar(x%10 + '0');
   }

数位DP

int a,b;
int upperBound[MAXN]; //每个位的最大值
int dp[MAXN][MAXN];
int split(int x) //分割位
{
    int ptr=0;
    while(x)
        upperBound[ptr++]=x%10,x/=10;
    return ptr;
}
int split(string x)
{
    for(int i=0; i<x.size(); i++)
        upperBound[i]=x[x.size()-i-1];
    return x.size();
}
int dfs(int pos,int pre_num,bool lead,bool flag)
{
    if(pos==-1)
        return 1;
    if(!flag&&dp[pos][pre_num]!=-1)
        return dp[pos][pre_num];
    int up=flag?upperBound[pos]:9,ret=0;
    for(int i=0;i<=up;i++)
        if(abs(i-pre_num)>=2||lead&&i==0)
            ret+=dfs(pos-1,i,lead&&i==0,flag&&i==up);
    if(!flag&&!lead)
        dp[pos][pre_num]=ret;
    return ret;
}
int solve(int x) //求出1~x满足条件的数的个数
{
    if(x<0)return 0;
    memset(dp,-1,sizeof(dp));
    int len=split(x);
    return dfs(len-1,0,1,1);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值