【ACM模板】~持续更新

1、倍增法求LCA

#include
using namespace std;
const int maxn = 500600;
int lg[maxn];
struct edge{
	int v,nxt;
}e[maxn<<1];
int fa[maxn][22];
int depth[maxn*10];
int head[maxn];
int ecnt;
void init(){
	ecnt=0;
	memset(head,-1,sizeof(head)); 
}
void addedge(int u,int v){
	e[ecnt].v=v;
	e[ecnt].nxt=head[u];
	head[u]=ecnt++;
}
void dfs(int f,int father){
	depth[f]=depth[father]+1;
	fa[f][0]=father;
	for(int i=1;(1<<i)<=depth[f];i++){
		fa[f][i]=fa[fa[f][i-1]][i-1];
	}
	for(int i=head[f];i+1;i=e[i].nxt){
		if(e[i].v!=father){
			dfs(e[i].v,f);
		}
	}
}
int lca(int x,int y){
	if(depth[x]<depth[y]){
		swap(x,y);
	}
	while(depth[x]>depth[y]){
		x=fa[x][lg[depth[x]-depth[y]]-1];
	}
	if(x==y) return x;
	for(int k=lg[depth[x]];k>=0;k--){
		if(fa[x][k]!=fa[y][k]){
			x=fa[x][k];
			y=fa[y][k];
		}
	}
	return fa[x][0];
}
int main(){
	int n,m,s,x,y;
	scanf("%d %d %d",&n,&m,&s);
	init();
	for(int i=1;i<=n-1;i++){
		scanf("%d %d",&x,&y);
		addedge(x,y);
		addedge(y,x);
	}
	dfs(s,0);
	for(int i=1;i<=n;i++){
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
	}
	for(int i=1;i<=m;i++){
		scanf("%d %d",&x,&y);
		printf("%d\n",lca(x,y));
	}
	return 0;
}

2、组合数+阶乘逆元打表

void init(){
    fact[0]=inv[1]=factinv[0]=inv[0]=fact[1]=factinv[1]=1;
    for(int i=2;i<=MAXN;i++){
        fact[i]=(fact[i-1]%mod*i%mod)%mod;
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        factinv[i]=factinv[i-1]*inv[i]%mod;
    }
}
ll c(ll n,ll m){
    return fact[n]*factinv[m]%mod*factinv[n-m]%mod;
}

3、EK算法求网络最大流

#include
using namespace std;
const int maxn = 105000;
const int INF = 0x3f3f3f3f;
struct edge{
    int v,w,nxt;
}e[maxn<<1]; 
int head[maxn];
int cnt=0;
bool vis[maxn];
struct node{
    int id,v;
}pre[maxn];
int n,m,s,t,a,b,c;
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
}
void addedge(int u,int v,int w){
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}
bool bfs(int s,int t){
    queue<int> q;
    memset(vis,0,sizeof(vis));
    memset(pre,0,sizeof(pre));
    q.push(s);
    pre[s].v=s;
    vis[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];i+1;i=e[i].nxt){
            int v=e[i].v;
            if(!vis[v]&&e[i].w){
                vis[v]=1;
                pre[v].v=u;
                pre[v].id=i;
                if(v==t) return true;
                q.push(v);
            }
        }
    }
    return false;
}
int EK(int s,int t){
    int ans=0;
    int minn;
    while(bfs(s,t)){
        minn=INF;
        for(int i=t;i!=s;i=pre[i].v){
            minn=min(minn,e[pre[i].id].w);
        }
        for(int i=t;i!=s;i=pre[i].v){
            e[pre[i].id].w-=minn;
            e[pre[i].id^1].w+=minn;
        }
        ans+=minn;
    }
    return ans;
}
int main(){
    cin>>n>>m;
    init();
    for(int i=1;i<=m;i++){
        cin>>a>>b>>c;
        addedge(a,b,c);
        addedge(b,a,0);
    }
    cout<<EK(1,n)<<endl;
    return 0;
}
	

4、dinic求最大流

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define N 2000001
#define M 8000010
#define inf 1<<26
#define p(a,b) m*(a-1)+b
using namespace std;
inline int read()
{
	int x=0,f=1;char ch;
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int n,m,ss,tt;
int head[N],pos=-1,cur[N];
struct edge{int to,next,c;}e[M];
void addedge(int a,int b,int c)
{pos++;e[pos].to=b,e[pos].next=head[a],e[pos].c=c,head[a]=pos;}
 
queue<int>Q;bool vis[N];int d[N];
bool bfs()
{
	for(int i=ss;i<=tt;i++)vis[i]=0,d[i]=-1;
	while(!Q.empty())Q.pop();
	d[ss]=0,vis[ss]=1;Q.push(ss);
	while(!Q.empty())
	{
		int u=Q.front();Q.pop();
		for(int i=head[u];i!=-1;i=e[i].next)
		{
			int v=e[i].to;
			if(e[i].c<=0||vis[v])
				continue;
			d[v]=d[u]+1;
			vis[v]=1;Q.push(v);
			//if(v==t)return true;
		}
	}return vis[tt];
}
int dfs(int u,int a)
{
	if(u==tt||!a)return a;
	int flow=0,f;
	for(int &i=cur[u];i!=-1;i=e[i].next)
	{
		int v=e[i].to;
		if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c)))>0)
		{
			flow+=f,a-=f;
			e[i].c-=f,e[i^1].c+=f;
			if(!a)break;
		}
	}return flow;
}
int dinic()
{
	int ret=0;
	while(bfs())
	{
		for(int i=ss;i<=tt;i++)cur[i]=head[i];
		ret+=dfs(ss,inf); 
	}return ret;
}
void init(){memset(head,-1,sizeof(head));}

5、最小费用最大流

#include
using namespace std;
const int maxn = 100050;
const int INF = 0x3f3f3f3f;
int head[maxn];
bool vis[maxn];
int dis[maxn];
int flow[maxn];
int n,m,s,t;
struct edge{
    int v,f,c,next;
}e[maxn];
struct node{
    int id;
    int v;
}pre[maxn];
int cnt;
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
}
void addedge(int u,int v,int f,int c){
    e[cnt].v=v;
    e[cnt].f=f;
    e[cnt].c=c;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
bool spfa()
{
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(flow,INF,sizeof(flow));
    queue<int>que;
    que.push(s);dis[s]=0;
    while(!que.empty())
    {
        int u=que.front();que.pop();
        vis[u]=0;
        for(int i=head[u];i+1;i=e[i].next)
        {
            int v=e[i].v,di=e[i].c,c=e[i].f;
            if(c&&dis[v]>dis[u]+di)
            {
                dis[v]=dis[u]+di;
                pre[v].id=i;//存v点在head数组里的位置
                pre[v].v=u;//存v点的父亲u
                flow[v]=min(c,flow[u]);
                //
                if(!vis[v])
                {
                    que.push(v);vis[v]=1;
                }
            }
        }
    }
    return flow[t]!=flow[s];//判断T是否能被便利
}
void MCMF()
{
    int mf=0;
    int mc=0;
    while(spfa())
    {
        mf+=flow[t];//更新最大流
        mc+=flow[t]*dis[t];//更新最小费用
        for(int u=t;u!=s;u=pre[u].v)//从T返回沿路径修改剩余容量
        {
            int v=pre[u].id;
            e[v].f-=flow[t];//正边减掉增广量
            e[v^1].f+=flow[t];//反边减掉增广量
        }
    }
    printf("%d %d\n",mf,mc);
}
int main(){
    init();
    cin>>n>>m>>s>>t;
    int u,v,f,c;
    for(int i=1;i<=m;i++){
        cin>>u>>v>>f>>c;
        addedge(u,v,f,c);
        addedge(v,u,0,-c);
    }
    MCMF();
    return 0;
}

6、高精度加法

#include
#include
#include
using namespace std;
const int L=11000;
string add(string a,string b)//只限两个非负整数相加
{
    string ans;
    int na[L]={0},nb[L]={0};
    int la=a.size(),lb=b.size();
    for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
    for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
    int lmax=la>lb?la:lb;
    for(int i=0;i<lmax;i++) na[i]+=nb[i],na[i+1]+=na[i]/10,na[i]%=10;
    if(na[lmax]) lmax++;
    for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
    return ans;
}
int main()
{
    string a,b;
    while(cin>>a>>b) cout<<add(a,b)<<endl;
    return 0;
}

7、高精度减法

#include
#include
#include
using namespace std;
const int L=11000;
string sub(string a,string b)//只限大的非负整数减小的非负整数
{
    string ans;
    int na[L]={0},nb[L]={0};
    int la=a.size(),lb=b.size();
    for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';
    for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';
    int lmax=la>lb?la:lb;
    for(int i=0;i<lmax;i++)
    {
        na[i]-=nb[i];
        if(na[i]<0) na[i]+=10,na[i+1]--;
    }
    while(!na[--lmax]&&lmax>0)  ;lmax++;
    for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
    return ans;
}
int main()
{
    string a,b;
    while(cin>>a>>b) {
        if(a.length()<b.length()){
            cout<<"-"<<sub(b,a)<<endl;
        }
        else if(a.length()==b.length()){
            if(a<b) cout<<"-"<<sub(b,a)<<endl;
            else cout<<sub(a,b)<<endl;
        }
        else cout<<sub(a,b)<<endl;
    }
    return 0;
}

8、高精度乘法

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define L(x) (1 << (x))
const double PI = acos(-1.0);
const int Maxn = 133015;
double ax[Maxn], ay[Maxn], bx[Maxn], by[Maxn];
char sa[Maxn/2],sb[Maxn/2];
int sum[Maxn];
int x1[Maxn],x2[Maxn];
int revv(int x, int bits)
{
    int ret = 0;
    for (int i = 0; i < bits; i++)
    {
        ret <<= 1;
        ret |= x & 1;
        x >>= 1;
    }
    return ret;
}
void fft(double * a, double * b, int n, bool rev)
{
    int bits = 0;
    while (1 << bits < n) ++bits;
    for (int i = 0; i < n; i++)
    {
        int j = revv(i, bits);
        if (i < j)
            swap(a[i], a[j]), swap(b[i], b[j]);
    }
    for (int len = 2; len <= n; len <<= 1)
    {
        int half = len >> 1;
        double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len);
        if (rev) wmy = -wmy;
        for (int i = 0; i < n; i += len)
        {
            double wx = 1, wy = 0;
            for (int j = 0; j < half; j++)
            {
                double cx = a[i + j], cy = b[i + j];
                double dx = a[i + j + half], dy = b[i + j + half];
                double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
                a[i + j] = cx + ex, b[i + j] = cy + ey;
                a[i + j + half] = cx - ex, b[i + j + half] = cy - ey;
                double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
                wx = wnx, wy = wny;
            }
        }
    }
    if (rev)
    {
        for (int i = 0; i < n; i++)
            a[i] /= n, b[i] /= n;
    }
}
int solve(int a[],int na,int b[],int nb,int ans[])
{
    int len = max(na, nb), ln;
    for(ln=0; L(ln)<len; ++ln);
    len=L(++ln);
    for (int i = 0; i < len ; ++i)
    {
        if (i >= na) ax[i] = 0, ay[i] =0;
        else ax[i] = a[i], ay[i] = 0;
    }
    fft(ax, ay, len, 0);
    for (int i = 0; i < len; ++i)
    {
        if (i >= nb) bx[i] = 0, by[i] = 0;
        else bx[i] = b[i], by[i] = 0;
    }
    fft(bx, by, len, 0);
    for (int i = 0; i < len; ++i)
    {
        double cx = ax[i] * bx[i] - ay[i] * by[i];
        double cy = ax[i] * by[i] + ay[i] * bx[i];
        ax[i] = cx, ay[i] = cy;
    }
    fft(ax, ay, len, 1);
    for (int i = 0; i < len; ++i)
        ans[i] = (int)(ax[i] + 0.5);
    return len;
}
string mul(string sa,string sb)
{
    int l1,l2,l;
    int i;
    string ans;
    memset(sum, 0, sizeof(sum));
    l1 = sa.size();
    l2 = sb.size();
    for(i = 0; i < l1; i++)
        x1[i] = sa[l1 - i - 1]-'0';
    for(i = 0; i < l2; i++)
        x2[i] = sb[l2-i-1]-'0';
    l = solve(x1, l1, x2, l2, sum);
    for(i = 0; i<l || sum[i] >= 10; i++) // 进位
    {
        sum[i + 1] += sum[i] / 10;
        sum[i] %= 10;
    }
    l = i;
    while(sum[l] <= 0 && l>0)    l--; // 检索最高位
    for(i = l; i >= 0; i--)    ans+=sum[i] + '0'; // 倒序输出
    return ans;
}
int main()
{
    cin.sync_with_stdio(false);
    string a,b;
    while(cin>>a>>b) cout<<mul(a,b)<<endl;
    return 0;
}

9、高精度除法

#include
#include
#include
using namespace std;
const int L=11000;
int sub(int *a,int *b,int La,int Lb)
{
    if(La<Lb) return -1;//如果a小于b,则返回-1
    if(La==Lb)
    {
        for(int i=La-1;i>=0;i--)
            if(a[i]>b[i]) break;
            else if(a[i]<b[i]) return -1;//如果a小于b,则返回-1

    }
    for(int i=0;i<La;i++)//高精度减法
    {
        a[i]-=b[i];
        if(a[i]<0) a[i]+=10,a[i+1]--;
    }
    for(int i=La-1;i>=0;i--)
        if(a[i]) return i+1;//返回差的位数
    return 0;//返回差的位数

}
string div(string n1,string n2,int nn)//n1,n2是字符串表示的被除数,除数,nn是选择返回商还是余数
{
    string s,v;//s存商,v存余数
     int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形数组表示被除数,除数,tp保存被除数的长度
     fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//数组元素都置为0
     for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
     for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
     if(La<Lb || (La==Lb && n1<n2)) {
            //cout<<0<
     return n1;}//如果a
     int t=La-Lb;//除被数和除数的位数之差
     for(int i=La-1;i>=0;i--)//将除数扩大10^t倍
        if(i>=t) b[i]=b[i-t];
        else b[i]=0;
     Lb=La;
     for(int j=0;j<=t;j++)
     {
         int temp;
         while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除数比除数大继续减
         {
             La=temp;
             r[t-j]++;
         }
     }
     for(i=0;i<L-10;i++) r[i+1]+=r[i]/10,r[i]%=10;//统一处理进位
     while(!r[i]) i--;//将整形数组表示的商转化成字符串表示的
     while(i>=0) s+=r[i--]+'0';
     //cout<
     i=tp;
     while(!a[i]) i--;//将整形数组表示的余数转化成字符串表示的
     while(i>=0) v+=a[i--]+'0';
     if(v.empty()) v="0";
     //cout<
     if(nn==1) return s;
     if(nn==2) return v;
}
int main()
{
    string a,b;
    while(cin>>a>>b) cout<<div(a,b,1)<<endl;
    return 0;
}

10、整除分块

for(int l=1,r;l<=n;l=r+1)
{
    r=n/(n/l);
    ans+=(r-l+1)*(n/l);
}

11、分层图最短路

#include
using namespace std;
const int maxn = 1500050;
const int INF = 0x3f3f3f3f;
int n,m,k;
int vis[maxn];
int head[maxn];
int st,ed;
int cnt;
int dis[maxn];
struct EDGE{
    int from;
    int to;
    int val;
    int next;
}e[maxn<<1];
struct node{
    int id;
    int d;
};
bool operator< (node a,node b){
    return a.d>b.d;
}
void init(){
    cnt=1;
    memset(head,-1,sizeof(head));
}
void addedge(int a,int b,int c){
    e[cnt].from=a;
    e[cnt].to=b;
    e[cnt].val=c;
    e[cnt].next=head[a];
    head[a]=cnt++;
}
void dij(int st,int ed){
    memset(dis,0x3f,sizeof(dis));
    priority_queue<node> q;
    node nt;
    nt.id=st,nt.d=0;
    dis[st]=0;
    q.push(nt);
    while(!q.empty()){
        node rt=q.top();
        q.pop();
        if(vis[rt.id]) continue;
        vis[rt.id]=1;
        for(int i=head[rt.id];i!=-1;i=e[i].next){
            if(dis[e[i].to]>dis[rt.id]+e[i].val){
                dis[e[i].to]=dis[rt.id]+e[i].val;
                nt.id=e[i].to;
                nt.d=dis[e[i].to];
                q.push(nt);
            }
        }
    }
    int ans=INF;
    for(int i=0;i<=k;i++){
        ans=min(ans,dis[i*n+ed]);
    }
    printf("%d\n",ans);
}
int main(){
    init();
    scanf("%d %d %d %d %d",&n,&m,&k,&st,&ed);
    int a,b,c;
    for(int i=1;i<=m;i++){
        scanf("%d %d %d",&a,&b,&c);
        for(int j=0;j<=k;j++){
            addedge(a+j*n,b+j*n,c);//构造每一层
            addedge(b+j*n,a+j*n,c);
            if(j!=k){
                addedge(a+j*n,b+(j+1)*n,0);//每层的权值为0
                addedge(b+j*n,a+(j+1)*n,0);
            }
        }
    }
    dij(st,ed);
    return 0;
}

12、卡特兰数打表

#include
#include
using namespace std;
int ans[200][3000];
void ktl()//卡特兰打表
{
    ans[1][0]=1;
    ans[2][0]=1;
    ans[1][1]=1;
    ans[2][1]=2;
    int len=1;
    int carry;
    for(int i=3;i<=102;i++)
    {
        carry=0;//余数
        for(int j=1;j<=len;j++)
        {
            int t=ans[i-1][j]*(4*i-2)+carry;//先求分子
            carry=t/10;
            ans[i][j]=t%10;
        }
        while(carry)
        {
            ans[i][++len]=carry%10;
            carry/=10;
        }
        for(int j=len;j>=1;j--)
        {
            int t=ans[i][j]+carry*10;
            ans[i][j]=t/(i+1);
            carry=t%(i+1);
        }
        while(!ans[i][len])
        {
            len--;
        }
        ans[i][0]=len;
    }
}
int main()
{
    ktl();
    int n;
    while(cin>>n)
    {
        for(int i=ans[n][0];i>0;i--)
        {
            cout<<ans[n][i];
        }
        cout<<endl;
    }
    return 0;
}

13、矩阵快速幂

#include
using namespace std;
typedef long long ll;
const ll maxn = 10;
const ll mod = 1000000009; 
struct mart{
	ll m[100][100];
}unit;
mart mult(mart a,mart b){
	mart ans;
	int x;
	for(ll i=0;i<4;i++){
		for(ll j=0;j<4;j++){
			x=0;
			for(ll k=0;k<4;k++){
				x=(x%mod+(a.m[i][k]%mod*b.m[k][j]%mod)%mod)%mod;
			}
			ans.m[i][j]=x%mod;
		}
	}
	return ans;
} 
void init(){
	for(ll i=0;i<4;i++){
		unit.m[i][i]=1;
	}
}
mart qpow(mart a,ll b){
	init();
	mart ans=unit;
	while(b){
		if(b&1) ans=mult(ans,a);
		a=mult(a,a);
		b>>=1;
	}
	return ans;
}
ll solve(ll n){
	mart a,b;
	a.m[0][0]=1;
	a.m[0][1]=1;
	a.m[1][0]=1;
	a.m[1][1]=0;
	
	b.m[0][0]=1;
	b.m[1][0]=0;
	mart c=mult(qpow(a,n-2),b);
	return c.m[0][0]%mod;
}
int main(){
	ll n;
	cin>>n;
	if(n==0) puts("0");
	else
	cout<<solve(n+1)<<endl;
	return 0;
}

14、最短路(dijkstra:链式前向星)

#include
using namespace std;
typedef long long ll;
const int INF = 2147483647;
const int maxn = 1005000;
struct node{
    ll d;
    int u;
};
bool operator<(node a,node b){
    return a.d>b.d; 
}
struct edge{
    int v,w,nxt;
}e[maxn<<1];
int head[maxn];
bool vis[maxn];
ll dis[maxn];
int n,m,cnt;
void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
}
void addedge(int u,int v,int w){
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}
void dij(int s){
    priority_queue<node> q;
    for(int i=1;i<=n;i++){
        dis[i]=INF;
    }
    dis[s]=0;
    memset(vis,0,sizeof(vis));
    node tn;
    tn.d=0;
    tn.u=s;
    q.push(tn);
    while(!q.empty()){
        node rt=q.top();q.pop();
        int u=rt.u;
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];i+1;i=e[i].nxt){
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w){
                dis[v]=dis[u]+e[i].w;
                tn.d=dis[v];
                tn.u=v;
                q.push(tn);
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(0);
    int s;
    init();
    cin>>n>>m>>s;
    int a,b,c;
    for(int i=1;i<=m;i++){
        cin>>a>>b>>c;
        addedge(a,b,c);
    }
    dij(s);
    for(int i=1;i<=n;i++){
        if(i!=1) cout<<" "<<dis[i];
        else cout<<dis[i];
    }
    cout<<endl;
    return 0;
}

你可能感兴趣的:(ACM)