【转载】常考算法模板

字符串

KMP

const int N=1000005;
char s[N], t[N];
int len_s, len_t, nxt[N];
void GetNext(char *s)
{
    for (int i=2, k=0; i<=len_s; i++)
    {
        while (k && s[i]!=s[k+1]) k=nxt[k];
        if (s[i]==s[k+1]) k++; nxt[i]=k;
    }
}

void KMP(char *s, char *t)
{
    for (int i=1, k=0; i<=len_t; i++)
    {
        while (k && t[i]!=s[k+1]) k=nxt[k];
        if (t[i]==s[k+1]) k++; 
        if (k==len_s){printf("%d\n", i-len_s+1); k=nxt[k];}
    }
}

SAM

inline void chkmax(int &x, int y){x<y?(x=y):0;}
inline void chkmin(int &x, int y){x>y?(x=y):0;}
const int N=1000005;
int son[N<<1][100], fa[N], len[N], last, cnt, n;//insert
int a[N], t[N], size[N];//sort
int mn[N], mx[N];//Get_N_LCS
int sum[N];//Get_Kth_Substr
int dp[N];//Get_N_Substr
long long ans;//Dif_Substr_Num
char s[N];

namespace SuffixAutoMaton
{
	void clear()//for Dif_Substr_Num
	{
		memset(fa, 0, sizeof(fa));
		memset(len, 0, sizeof(len));
		memset(son, 0, sizeof(son));
		ans=0; 
	}
	
    void insert(int c)
    {
        int p=last, np=last=++cnt; len[np]=len[p]+1;
        for (; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
        if (!p) fa[np]=1;
        else
        {
            int q=son[p][c]; 
            if (len[p]+1==len[q]) fa[np]=q;
            else
            {
                int nq=++cnt; len[nq]=len[p]+1;
                memcpy(son[nq], son[q], sizeof(son[q]));
                fa[nq]=fa[q]; fa[q]=fa[np]=nq;
                for (; son[p][c]==q; p=fa[p]) son[p][c]=nq;
            }
        }
        size[np]=1; 
		//ans+=len[np]-len[fa[np]]; //for Dif_Substr_Num
    }
    
    void Sort()
    {
    	for (int i=1; i<=cnt; i++) t[len[i]]++;
        for (int i=1; i<=cnt; i++) t[i]+=t[i-1];
        for (int i=1; i<=cnt; i++) a[t[len[i]]--]=i;
        for (int i=cnt; i; i--) size[fa[a[i]]]+=size[a[i]];
    }
    
    void build()
    {
        scanf("%s", s+1); last=cnt=1; n=strlen(s+1);
    	for (int i=1; i<=n; i++) insert(s[i]-'A');
    }
    
    void Get_LCS()
    {
        build(); scanf("%s", s+1); 
        int n=strlen(s+1), p=1, Len=0, ans=0;
        for (int i=1; i<=n; i++)
        {
            int c=s[i]-'a';
            if (son[p][c]) p=son[p][c], Len++;
            else
            {
                for (; p&&!son[p][c]; p=fa[p]);
                if (p) Len=len[p]+1, p=son[p][c];
                    else p=1, Len=0;
            }
            ans=max(ans, Len);
        }
        printf("%d\n", ans);
    }
    
    void Get_N_LCS()
    {
        memset(mn, 0x3f, sizeof(mn)); 
		build(); Sort(); int ans=0;
        while (~scanf("%s", s+1))
        {
            int n=strlen(s+1), p=1, Len=0;
            for (int i=1; i<=n; i++)
            {
                int c=s[i]-'a';
                if (son[p][c]) Len++, p=son[p][c], chkmax(mx[p], Len);
                else
                {
                    for (; p&&!son[p][c]; p=fa[p]);
                    if (p) Len=len[p]+1, p=son[p][c], chkmax(mx[p], Len);
                        else Len=0, p=1;
                }
            }
            for (int i=cnt; i; i--)
            {
                int u=a[i];
                chkmax(mx[fa[u]], min(mx[u], len[fa[u]]));
                chkmin(mn[u], mx[u]); mx[u]=0;
            }
        }
        for (int i=1; i<=cnt; i++) chkmax(ans, mn[i]);
        printf("%d\n", ans);
    }
    
    void Get_Kth_Dif_Substr()
    {
    	Sort();
    	for (int i=1; i<=cnt; i++) sum[i]=size[i]=1; sum[1]=size[1]=0;
    	for (int i=cnt; i; i--) 
        	for (int j=0; j<26; j++) sum[a[i]]+=sum[son[a[i]][j]];
    	int k=read(), u=1; 
		if (sum[1]<k) {puts("-1"); exit(0);}
        while (k>0)
        {
            for (int i=0; i<26; i++) if (son[u][i])
            {
                if (sum[son[u][i]]<k) k-=sum[son[u][i]];
                    else{putchar(i+'a'); u=son[u][i]; k--; break;}
            }
        }
        puts("");
    }
    
    void Get_Kth_Substr()
    {
    	Sort();
    	for (int i=1; i<=cnt; i++) sum[i]=size[i]; sum[1]=size[1]=0;
   	    for (int i=cnt; i; i--) 
        	for (int j=0; j<26; j++) sum[a[i]]+=sum[son[a[i]][j]];
		int k=read(), u=1; if (sum[1]<k) {puts("-1"); exit(0);}
		while (k>0)
	    {
	        for (int i=0; i<26; i++) if (son[u][i])
	        {
	            if (sum[son[u][i]]<k) k-=sum[son[u][i]];
	                else{putchar(i+'a'); u=son[u][i]; k-=size[u]; break;}
	        }
	    }
	    puts("");
	}
	
	void Get_N_Substr()
	{
		build(); Sort();
		for (int i=cnt; i; i--) chkmax(dp[len[a[i]]], size[a[i]]);
		for (int i=n-1; i; i--) chkmax(dp[i], dp[i+1]);
		for (int i=1; i<=n; i++) printf("%d\n", dp[i]);
	}
	
	void Dif_Substr_Num()
	{
		int T=read();
		while (T--) clear(), build(), printf("%lld\n", ans);
	}	
}

SA

const int N=2000005;
int sa[N], rnk[N], top[N], tax[N], n, m;
int h[N], st[N][24], log_2[N];
char s[N];

namespace SuffixArray
{
    inline void SuffixSort()
    {
        scanf("%s", s+1); n=strlen(s+1); m=122;
        memset(tax, 0, sizeof(tax));
        for (int i=1; i<=n; i++) tax[rnk[i]=(int)s[i]]++;
        for (int i=1; i<=m; i++) tax[i]+=tax[i-1];
        for (int i=n; i; i--) sa[tax[rnk[i]]--]=i;
        for (int p=1; p<=n; p<<=1)
        {
            int t=0;
            for (int i=n-p+1; i<=n; i++) top[++t]=i;
            for (int i=1; i<=n; i++) if (sa[i]>p) top[++t]=sa[i]-p;
            memset(tax, 0, sizeof(tax));
            for (int i=1; i<=n; i++) tax[rnk[i]]++;
            for (int i=1; i<=m; i++) tax[i]+=tax[i-1];
            for (int i=n; i; i--) sa[tax[rnk[top[i]]]--]=top[i];
            memcpy(top, rnk, sizeof(rnk)); rnk[sa[1]]=t=1;
            for (int i=2; i<=n; i++) 
                rnk[sa[i]]=(top[sa[i-1]]==top[sa[i]] 
                    && top[sa[i-1]+p]==top[sa[i]+p])? t : ++t;
            if (t==n) break; m=t;
        }
    }

    void Height()
    {
        int k=0;
        for (int i=1; i<=n; i++) rnk[sa[i]]=i;
        for (int i=1; i<=n; i++)
        {
            int j=sa[rnk[i]-1]; k?k--:0; 
            while (s[i+k]==s[j+k]) k++; h[rnk[i]]=k;
        }
    }
    
    void ST()
    {
        for (int i=1; i<=n; i++) st[i][0]=h[i+1];
        for (int p=1; (1<<p)<n; p++)
            for (int i=1; i+(1<<p)-1<=n; i++)
                st[i][p]=min(st[i][p-1], st[i+(1<<(p-1))][p-1]);
        log_2[1]=0;
        for (int i=2; i<=n; i++) log_2[i]=log_2[i>>1]+1;
    }
    
    int LCP(int l, int r)
    {
        int p=log_2[r-l+1];
        return min(st[l][p], st[r-(1<<p)+1][p]);
    }
}

AC自动机(Trie图)

const int N=1000005;
struct node{int fail, num, son[26];}t[N];
int cnt; char s[N];
namespace Aho_Corasick_Automaton
{	
	void insert(char *s)
	{
	    int len=strlen(s+1), p=0;
	    for (int i=1; i<=len; i++)
	    {
	        int c=s[i]-'a';
	        if (!t[p].son[c]) t[p].son[c]=++cnt;
	        p=t[p].son[c];
	    }
	    t[p].num++;
	}
	
	void build_AC()
	{
	    queue<int> q;
	    for (int i=0; i<26; i++) if (t[0].son[i]) q.push(t[0].son[i]);
	    while (!q.empty())
	    {
	        int now=q.front(), fail=t[now].fail; q.pop();
	        for (int i=0; i<26; i++)
	        {
	            int son=t[now].son[i];
	            if(son) t[son].fail=t[fail].son[i], q.push(son);
	                else t[now].son[i]=t[fail].son[i];
	        }
	    }
	}
	
	int find(char *s)
	{
	    int len=strlen(s+1), pos=0, res=0;
	    for (int i=1; i<=len; i++)
	    {
	        int c=s[i]-'a', now=pos=t[pos].son[c];
	        while (now && t[now].num!=-1)
	        {
	            res+=t[now].num; t[now].num=-1;
	            now=t[now].fail;
	        }
	    }
	    return res;
	}
	
	void Build()
	{
		for (int i=1, n=read(); i<=n; i++) 
			scanf("%s", s+1), insert(s);
		build_AC();
	}
}

Manacher

const int N=11000005;
char t[N], s[N<<1]; int p[N<<1];
int main()
{
	scanf("%s", t+1); int n=strlen(t+1), ans=0;
	for (int i=1; i<=n; i++) s[i<<1]=t[i], s[i<<1|1]='#';
	(n<<=1)+=2; s[1]=s[n]='#';
	for (int i=1, maxr=0, mid=0; i<=n; i++)
    {
        p[i]=(i<maxr)?min(p[2*mid-i], p[mid]+mid-i):1;
        while (i+p[i]<=n && s[i+p[i]]==s[i-p[i]]) p[i]++;
        if (p[i]+i>maxr) maxr=p[i]+i, mid=i;
    }
    for (int i=1; i<=n; i++) ans=max(ans, p[i]-1);
    printf("%d\n", ans);
	return 0;
}

最小表示法

int main()
{
	int n=read(), k=0, i=0, j=1;
	for (int i=0; i<n; i++) a[i]=read();
	while (k<n && i<n && j<n)
	{
		if (a[(i+k)%n]==a[(j+k)%n]) k++;
		else 
		{
			a[(i+k)%n]>a[(j+k)%n]?i=i+k+1:j=j+k+1;
			i==j?i++:0; k=0;
		}
	} j=min(i, j);
	for (int i=j; i<n; i++) printf("%d ", a[i]);
	for (int i=0; i<j; i++) printf("%d ", a[i]); 
}

数学

快速幂

int Pow(int x, int t)
{
    int res=1;
    while (t)
    {
        if (t&1) res=1ll*res*x%p;
        x=1ll*x*x%p; t>>=1;
    }
    return res;
}

逆元

	inv[1]=1; for (int i=2; i<=n; i++) inv[i]=1ll*(p-p/i)*inv[p%i]%p;//线性求逆元
	
	int fac=1; for (int i=1; i<=n; i++) fac=1ll*fac*i%p;
	ifac[n]=Pow(fac, p-2); for (int i=n-1; i; i--) ifac[i]=1ll*ifac[i+1]*(i+1)%p;//线性求阶乘逆元

void Exgcd(int a, int b, int &x, int &y)
{
	if (!b) x=1, y=0;
	else Exgcd(b, a%b, y, x), y-=a/b*x;
}
int inv(int a, int p)
{
	int x, y;
	Exgcd(a, p, x, y);
	return (x%p+p)%p;
}//扩展欧几里得求逆元

Lucas定理

int C(int n, int m)
{
	if (n<m) return 0;
	return (fac[n] * Pow(fac[m], p-2) % p) * Pow(fac[n-m], p-2) % p;
}
int Lucas(int n, int m, int p)
{
	if (!m) return 1;
	return Lucas(n/p, m/p) * C(n%p, m%p) % p;
}

线性基

for (int i=1; i<=n; i++)
{
    int x=read();
    for (int j=max_log; ~j; j--) if (x>>j)
        {if (!p[j]) {p[j]=x; break;} else x^=p[j];}
}
for (int i=max_log; i>=0; i--) ans=max(ans, ans^p[i]);
//Max_Xor_Sum

线性筛素数

void Euler_Prime(int n)
{
	memset(isprime, true, sizeof(isprime)); isprime[1]=0;
    int cnt=0;
    for (int i=2; i<=n; i++)
    {
        if (isprime[i]) prime[++cnt]=i;
        for (int j=1; j<=cnt && i*prime[j]<=n; j++)
        {
            isprime[i*prime[j]]=false;
            if (!(i%prime[j])) break;
        }
    }
}

void Get_Phi(int n)
{
	memset(isprime, true, sizeof(isprime)); isprime[1]=0;
    int cnt=0;
    for (int i=2; i<=n; i++)
    {
        if (isprime[i]) prime[++cnt]=i, phi[i]=i-1;
        for (int j=1; j<=cnt && i*prime[j]<=n; j++)
        {
            isprime[i*prime[j]]=0;
            if (!(i%prime[j])) {phi[i*prime[j]]=phi[i]*prime[j]; break;}
            	else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}

void Get_Mu(int n)
{
	memset(isprime, true, sizeof(isprime)); isprime[1]=0; mu[1]=1;
    int cnt=0;
    for (int i=2; i<=n; i++)
    {
        if (isprime[i]) prime[++cnt]=i, mu[i]=-1;
        for (int j=1; j<=cnt && i*prime[j]<=n; j++)
        {
            isprime[i*prime[j]]=0;
            if (!(i%prime[j])) break;
            	else mu[i*prime[j]]=-mu[i];
        }
    }
}

矩阵快速幂

struct Matrix
{
	int n, m; long long sq[N][N];
	
	Matrix(int _n, int _m){n=_n; m=_m; memset(sq, 0, sizeof(sq));}
	
	Matrix operator + (Matrix a)
	{
		Matrix ans(n, m);
		for(int i=1; i<=n; i++) for(int j=1; j<=m; j++)
			ans.sq[i][j]=(sq[i][j] + a.sq[i][j])%P;
		return ans;
	} 
	
	Matrix operator * (Matrix a)
	{
		Matrix ans(n, a.m);
		for(int i=1; i<=n; i++) for(int j=1; j<=a.m; j++)
		{
			long long tmp=0;
			for(int k=1; k<=m; k++)
				tmp=(tmp+((long long)sq[i][k]*a.sq[k][j])%P)%P; 
			ans.sq[i][j]=tmp;
		}
		return ans;
	}
};

Matrix Pow (Matrix a, long long n)
{
	Matrix ans(a.n, a.n), tmp(a.n, a.n);
	for(int i=1; i<=a.n; i++) ans.sq[i][i]=1;
	memcpy(tmp.sq, a.sq, sizeof(tmp.sq));
	while(n)
	{
		if(n&1) ans=ans*tmp;
		n>>=1; tmp=tmp*tmp;
	}
	return ans;
}

拉格朗日插值

int Lagrange(int *x, int *y, int n, int k)
{
    int res=0;
    for (int i=1; i<=n; i++)
    {
        int s1=1, s2=1;
        for (int j=1; j<=n; j++) if (i^j)
        {
            s1=1ll*s1*(k-x[j])%P;
            s2=1ll*s2*(x[i]-x[j])%P;
        }
        res=(res+1ll*(1ll*s1*Pow(s2, P-2)%P)*y[i])%P;
    }
    return (res%P+P)%P;
}//O(n^2)

int Lagrange(int *y,int n,int k)
{
	int ans=0, fac=1; pre[0]=suf[n+1]=1; ifac[n]=Pow(fac, P-2);
	for (int i=1; i<=n; i++) pre[i]=1ll*pre[i-1]*(k-i)%P;
	for (int i=n; i; i--) suf[i]=1ll*suf[i+1]*(k-i)%P;
    for (int i=1; i<=n; i++) fac=1ll*fac*i%P;
    for (int i=n-1; i; i--) ifac[i]=1ll*ifac[i+1]*(i+1)%P;
	for (int i=1; i<=n; i++)
	{
		int s1=1ll*pre[i-1]*suf[i+1]%P;
		int s2=1ll*ifac[i-1]*ifac[n-i]%P;
		ans=(ans+1ll*((n-i)&1?-1:1)*s1*s2%P*y[i])%P;
	}
	return (ans%P+P)%P;
}//O(n)

Miller Rabin

#define int long long
const int times=10;

int mul(int x, int t, int P)
{
	int res=0;
	for (; t; t>>=1, x=(x+x)%P) if (t&1) res=(res+x)%P;
	return res;
}

int Pow(int x, int t, int P)
{
	int res=1;
	for (; t; t>>=1, x=mul(x, x, P)) if (t&1) res=mul(res, x, P);
	return res;
}

bool check(int a, int p)
{
	int x=p-1, k=0;
	while (!(x&1)) x>>=1, k++;
	x=Pow(a, x, p);
	if (x==1) return true;
	rep(i, 1, k)
	{
		if (x==p-1) return true;
		x=mul(x, x, p);
	}
	return false;
}

bool Miller_Rabin(int x)
{
	if (x==2) return true; 
	if (x<2) return false;
	rep(i, 1, times) 
	{
		int a=rand()%(x-2)+2;
		if (!check(a, x)) return false;
	}
	return true;
}

Pollard Rho

#define int long long

const int times=10;
int max(int a, int b){return a>=b?a:b;}
int sub(int a, int b){return a>=b?a-b:b-a;}
int gcd(int a, int b){return b?gcd(b, a%b):a;}
int mul(int x, int y, int P) 
{
	int t=(long double)x*y/P;
	return ((x*y-t*P)%P+P)%P;
}	
int Pow(int x, int t, int P)
{
	int res=1;
	for (; t; t>>=1, x=mul(x, x, P)) if (t&1) res=mul(res, x, P);
	return res;
}

bool check(int a, int p)
{
	int x=p-1, k=0;
	while (!(x&1)) x>>=1, k++;
	x=Pow(a, x, p);
	if (x==1) return true;
	rep(i, 1, k)
	{
		if (x==p-1) return true;
		x=mul(x, x, p);
	}
	return false;
}

bool Miller_Rabin(int x)
{
	if (x==2) return true; 
	if (x<2) return false;
	rep(i, 1, times) 
	{
		int a=rand()%(x-2)+2;
		if (!check(a, x)) return false;
	}
	return true;
}


int solve(int n, int step, int add)
{
	if (!(n&1)) return 2;
	int x=2, y=2, d=1;
	while (1)
	{
		int tx=x, ty=y;
		rep(i, 1, step)
		{
			x=mul(x, x, n)+add; if (x>=n) x-=n;
			y=mul(y, y, n)+add; if (y>=n) y-=n;
			y=mul(y, y, n)+add; if (y>=n) y-=n;
			d=mul(d, sub(x, y), n);
		}
		d=gcd(n, d);
		if (d==1) continue;
		if (d^n) return d;
		x=tx; y=ty;
		rep(i, 1, step)
		{
			x=mul(x, x, n)+add; if (x>=n) x-=n;
			y=mul(y, y, n)+add; if (y>=n) y-=n;
			y=mul(y, y, n)+add; if (y>=n) y-=n;
			d=gcd(n, sub(x, y));
			if (d^1) return d%n;
		}
		return 0;
	}
}

int Rho(int n)
{
	if (Miller_Rabin(n)) return n; 
	int tmp=0, step=pow(n, 0.1), add=0;
	while (!tmp) tmp=solve(n, step, ++add);
	return max(Rho(tmp), Rho(n/tmp));
}

原根

void Sieve(int MAX)
{
	for (int i=2; i<=MAX; i++)
	{
		if (!vis[i]) p[++cnt]=i;
		for (int j=1; j<=cnt && p[j]*i<=MAX; j++)
		{
			vis[p[j]*i]=1;
			if (!(i%p[j])) break;
		}
	}
}

int Pow(int x, int t)
{
	int res=1;
	for (; t; t>>=1, x=1ll*x*x%P) if (t&1) res=1ll*res*x%P;
	return res;
}

void GetFactor(int n)
{
	for (int i=1; i<=cnt; i++) 
	{
		if (n<p[i]*p[i]) return;
		if (!(n%p[i])) fac[++tot]=p[i];
	}
}

bool IsRoot(int n)
{
	for (int i=1; i<=tot; i++)
		if (Pow(n, (P-1)/fac[i])==1) return false;
	return true;
}

int GetRoot(int P);
{
	Sieve(31623); GetFactor(P-1);
	for (int i=2; ; i++) if (IsRoot(i)) return i;
}

康托展开

void Add(int x, int d){for (; x <= n; x += x & -x) t[x] += d;}
int Query(int x)
{
	int res = 0;
	for (; x; x -= x & -x) res += t[x];
	return res;
}

int Cantor()
{
	n = read(); fac[0] = 1;
	for (int i = 1; i <= n; ++i) p[i] = read();
	for (int i = 1; i <= n; ++i) fac[i] = mul(fac[i - 1], i);
	for (int i = 1; i <= n; ++i) Add(i, 1);
	for (int i = 1; i <= n; ++i)
	{
		ans=add(ans, mul(sub(Query(p[i]), 1), fac[n - i]));
		Add(p[i], -1);
	}
	return add(ans, 1);
}

图论

最大流(Dinic)

const int N = 500, M = 1000;
struct node{int to, nxt, flow;}edge[M];
int head[N], cur[N], dep[N], cnt, n, S, T;
void pre(){memset(head, -1, sizeof(head)); cnt=-1;}

void add(int u, int v, int w)
{
    edge[++cnt] = (node){v, head[u], w};
    head[u] = cnt;
    
    edge[++cnt] = (node){u, head[v], 0};
    head[v] = cnt;
}

bool bfs()
{
    memset(dep, 0, sizeof(dep)); 
	dep[S] = 1;
	
    queue<int> q; 
	q.push(S);
	
    memcpy(cur, head, sizeof(head));
    
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (int i = head[u]; ~i; i = edge[i].nxt)
        {
            int v = edge[i].to, f = edge[i].flow;
            if (f && !dep[v]) dep[v] = dep[u] + 1, q.push(v);
        }
    }
    
    return dep[T];
}

int dfs(int u, int lim)
{
    if (!lim || u == T) return lim;
    
    int addflow = 0, flow;
    for (int i = cur[u]; ~i; i = edge[i].nxt)
    {
        cur[u] = i; 
		int v = edge[i].to, f = edge[i].flow;
		
        if (dep[v] == dep[u] + 1 && (flow = dfs(v, min(lim, f))))
        {
            addflow += flow; 
			lim -= flow;
            edge[i].flow -= flow; 
			edge[i ^ 1].flow += flow;
			
            if (!lim) break;
        }
    }
    
    return addflow;
}

int Dinic()
{
    int maxflow = 0;
    while (bfs()) 
		maxflow += dfs(S, 1<<30);
    return maxflow;
}


费用流(EK&spfa)

const int N=10005, M=1000005;
struct node{int to, nxt, flow, cost;}edge[M];
int head[N], flow[N], cost[N], pre[N], last[N], cnt;
int vis[N], S, T;
void prep(){memset(head, -1, sizeof(head)); cnt=-1;}

void add(int u, int v, int f, int w)
{
    edge[++cnt]=(node){v, head[u], f, w};
    head[u]=cnt;
    edge[++cnt]=(node){u, head[v], 0, -w};
    head[v]=cnt;
}

bool spfa()
{
    memset(cost, 0x3f, sizeof(cost)); cost[S]=0;
    memset(flow, 0x3f, sizeof(flow));
    memset(vis, 0, sizeof(vis)); vis[S]=1;
    queue<int> q; q.push(S); pre[T]=-1;
    while (!q.empty())
    {
        int u=q.front(); q.pop();
        for (int i=head[u]; ~i; i=edge[i].nxt)
        {
            vis[u]=0; 
            int v=edge[i].to, w=edge[i].cost, f=edge[i].flow;
            if (f>0 && cost[u]+w<cost[v])
            {
                cost[v]=cost[u]+w;
                pre[v]=u; last[v]=i;
                flow[v]=min(flow[u], f);
                if (!vis[v]) vis[v]=1, q.push(v);
            }
        }
    }
    return ~pre[T];
}

int EK()
{
    int maxflow=0, mincost=0;
    while (spfa())
    {
        maxflow+=flow[T]; mincost+=flow[T]*cost[T];
        int u=T;
        while (u^S)
        {
            edge[last[u]].flow-=flow[T];
            edge[last[u]^1].flow+=flow[T];
            u=pre[u];
        }
    }
    return mincost;
}

点分治(路径长为K

的条数)

inline void chkmax(int &x, int y){x<y?(x=y):0;}
const int N=10005;
vector<pair<int, int> > G[N];
int size[N], Max[N], dis[N], vis[N];
int sum, cnt, rt, n, m, K; long long ans;

#define v i.first
#define w i.second

void GetRoot(int u, int fa)
{
	size[u]=1; Max[u]=0;
	for (auto i: G[u]) if (v^fa && !vis[v])
		GetRoot(v, u), chkmax(Max[u], size[v]), size[u]+=size[v];	
	chkmax(Max[u], sum-size[u]);
	if (Max[u]<Max[rt]) rt=u;
}

int LeftBound(int l, int x)
{
	int ans=0, r=cnt;
	while (l<=r) 
	{
		int mid=l+r>>1;
		if (dis[mid]<x) l=mid+1; 
			else ans=mid, r=mid-1;
	}
	return ans;
}

int RightBound(int l, int x)
{
	int ans=0, r=cnt;
	while (l<=r)
	{
		int mid=l+r>>1;
		if (dis[mid]>x) r=mid-1;
			else ans=mid, l=mid+1;
	}
	return ans;
}

void GetDis(int u, int fa, int Dis)
{
	for (auto i: G[u]) if (v^fa && !vis[v])
		dis[++cnt]=Dis+w, GetDis(v, u, dis[cnt]);
}

int GetAns(int u, int Dis)
{
	dis[cnt=1]=Dis; GetDis(u, 0, Dis);
	sort(dis+1, dis+cnt+1);
	int l=1, ans=0;
	while (l<cnt && dis[l]+dis[cnt]<K) l++;
	while (l<cnt && (dis[l]<<1)<=K) 
	{
		int DisL=LeftBound(l+1, K-dis[l]);
		int DisR=RightBound(l+1, K-dis[l]);
		if (DisR>=DisL) ans+=DisR-DisL+1;
		l++;
	}
	return ans;
}

void dfs(int u)
{
	vis[u]=1; ans+=GetAns(u, 0); 
	for (auto i: G[u]) if (!vis[v])
	{
		ans-=GetAns(v, w); 
		sum=size[v]; rt=0; GetRoot(v, u); dfs(rt);
	} 
}

#undef v
#undef w

void add(int u, int v, int w)
{
	G[u].push_back(make_pair(v, w));
	G[v].push_back(make_pair(u, w));
}

朱刘算法(最小树形图)

const int N=105, M=10005, inf=0x3f3f3f3f;
struct edge{int u, v, w;}E[M];
int In_val[N], In_ver[N], vis[N], id[N], n, m, rt;

int ZhuLiu()
{
	int ans = 0;
	while (1)
	{
		memset(In_val, 0x3f, sizeof(In_val));
		for (int i = 1; i <= m; ++i)
		{
			int u = E[i].u, v = E[i].v, w = E[i].w;
			if (u ^ v && w < In_val[v]) In_val[v]=w, In_ver[v]=u;
		}
		for (int i = 1; i <= n; ++i) 
			if (i ^ rt && In_val[i] == inf) return -1;
		
		int cnt = 0;
		memset(vis, 0, sizeof(vis));
		memset(id, 0, sizeof(id));
		for (int i = 1; i <= n; ++i) if (i ^ rt)
		{
			int u = i; ans += In_val[u];
			while (vis[u] ^ i && !id[u] && u ^ rt)
				vis[u] = i, u = In_ver[u];
			while (!id[u] && u ^ rt)
			{
				id[u] = ++cnt;
				for (int v = In_ver[u]; v ^ u; v = In_ver[v]) id[v] = cnt;
			}
		}
		if (!cnt) return ans;
		
		for (int i = 1; i <= n; ++i) if (!id[i]) id[i] = ++cnt;		
		for (int i = 1; i <= m; ++i)
		{
			int u = E[i].u, v = E[i].v;
			E[i].u = id[u]; E[i].v = id[v];
			if (id[u] ^ id[v]) E[i].w -= In_val[v];
		}
		rt = id[rt]; n = cnt;
	}
}

数据结构

左偏树

int Merge(int x, int y)
{
	if (!x || !y) return x|y;
	if (a[x]<a[y] || (a[x]==a[y] && x>y)) swap(x, y);
	rs[x]=Merge(rs[x], y);
	if (dis[ls[x]]<dis[rs[x]]) swap(ls[x], rs[x]);
	dis[x]=dis[rs[x]]+1;
	return x;
}

int Delete(int x){return Merge(ls[x], rs[x]);}

多项式

FFT

const double pi = acos(-1.0);

namespace ComplexOperator
{
    struct complex
    {
        double x, y;
        complex(double _x = 0.0, double _y = 0.0) 
			{ x = _x; y = _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
		);
    }
    complex operator * (complex a, complex b)
    {
        return complex(
			a.x * b.x - a.y * b.y,
			a.x * b.y + a.y * b.x
		);
    }
}

using namespace ComplexOperator;

const int N = 4e6 + 5;

complex a[N], b[N]; 
int rev[N];

void FFT(complex *a, int n, int x)
{
    for (int i = 0; i < n; ++i) 
		if (i < rev[i]) swap(a[i], a[rev[i]]);
	
    for (int i = 1; i < n; i <<= 1)
    {
        complex Wn = complex(cos(pi / i), sin(pi / i) * x);
        for (int j = 0; j < n; j += (i << 1))
        {
            complex W = complex(1, 0);
            for (int k = 0; k < i; ++k, W = W * Wn)
            {
                complex A1 = a[j + k];
				complex A2 = W * a[i + j + k];
				
                a[j + k] = A1 + A2; 
				a[i + j + k] = A1 - A2;
            }
        }
    }
}

void multiply(complex a[], complex b[], int n, int m)
{
    int limit = 1, cnt = 0;
    while (limit <= n + m) limit <<= 1, ++cnt;
	
    for (int i = 0; i < limit; ++i) 
		rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (cnt - 1));
	
    FFT(a, limit, 1); 
	FFT(b, limit, 1);
    for (int i = 0; i <= limit; ++i) a[i] = a[i] * b[i];
    FFT(a, limit, -1);
    
    for (int i = 0; i <= n + m; ++i) a[i].x = (int)(a[i].x / limit + 0.5);
}

NTT

const int N=4000005, P=998244353, G=3;
inline int add(int x, int y){return x+y>=P?x+y-P:x+y;}
inline int sub(int x, int y){return x-y<0?x-y+P:x-y;}
inline int mul(int x, int y){return 1ll*x*y-1ll*x*y/P*P;}
int a[N], b[N], rev[N];

int Pow(int x, int t)
{
	int res=1;
	for (; t; t>>=1, x=mul(x, x)) if (t&1) res=mul(res, x);
	return res;
}

void NTT(int *a, int n, int x)
{
	for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i], a[rev[i]]);
	for (int mid=1, len=2; mid<n; mid<<=1, len<<=1)
	{
		int Gn=Pow(G, (P-1)/len);
		for (int i=0; i<n; i+=len)
		{
			int Gen=1;
			for (int j=0; j<mid; j++, Gen=mul(Gen, Gn))
			{
				int A1=a[i+j], A2=mul(Gen, a[i+j+mid]);
				a[i+j]=add(A1, A2); a[i+j+mid]=sub(A1, A2);
			}
		}
	}
	if (!~x) reverse(a+1, a+n);
}

void solve()
{
	int n=read(), m=read(), lim=1, cnt=0;
	while (lim<=n+m) lim<<=1, cnt++;
	rep(i, 0, n) a[i]=read();
	rep(i, 0, m) b[i]=read();
	rep(i, 0, lim) rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (cnt - 1));
	NTT(a, lim, 1); NTT(b, lim, 1);
	rep(i, 0, lim) a[i]=mul(a[i], b[i]);
	NTT(a, lim, -1);
	lim=Pow(lim, P-2);
	rep(i, 0, n+m) printf("%d ", mul(a[i], lim));
}

原文:https://www.cnblogs.com/ACMSN/p/10487023.html
posted @ 2020-12-21 08:31  OIER笔记  阅读(130)  评论(0编辑  收藏  举报
返回顶部↑
友情链接: SSOJ OIER博客 ABC题解 ChatGPT体验 WIKIOI