算法模板集合(动态规划+图论+数学)

附加C++常用STL库详细总结:点我跳转

算法模板集合

  • 1.树
    • 1.1字典树
    • 1.2线段树
    • 1.3树状数组
    • 1.4二叉树建树模板
    • 1.5二叉搜索树建树模板
    • 1.6树上启发式合并
    • 1.7多叉线段树(dfs序)
      • 1.7.1Dfs序代码
  • 2.并查集
  • 3.动态规划
    • 3.1背包
      • 3.1.101背包
      • 3.1.2多重背包
      • 3.1.3二维背包
      • 3.1.4分组背包
      • 3.1.5混合背包
      • 3.1.6完全背包
    • 3.2区间dp
    • 3.3树形dp
    • 3.4数位dp
    • 3.5最长公共子序列
    • 3.6最长上升子序列
  • 4.素数类
    • 4.1Min25筛
    • 4.2大于1e9的素数个数模板
  • 5.大数据
    • 5.1大数据处理(c++)
    • 5.2大数据处理(java)
    • 5.3Java大数算法
      • 5.3.1四则运算
      • 5.3.2Java大数阶乘
  • 6.逆序数
  • 7.STL类
    • 7.1常用STL库
    • 7.2容器set
  • 8.数学模板
    • 8.1卢卡斯定理求组合数模板
    • 8.2逆元法求组合数模板
  • 9.图
    • 9.1迪杰斯特拉/单源最短路模板
    • 9.2搜索模板
      • 9.2.1DFS深度优先搜索模板
      • 9.2.2BFS广度优先搜索模板

1.树

1.1字典树

#include
#include
using namespace std;
int letter=0;
char ans[500000][20],a[20],b[20];
struct node{
	int flag;
	node *word[26];
	node(){
		flag=0;
		for(int i=0;i<26;i++)word[i]=NULL;
	}
}*root;
void insert(node *p,char *s)//插入
{
	int len=strlen(s);
	for(int i=0;i<len;i++)
	{
		int num=s[i]-'a';
		if(p->word[num]==NULL)p->word[num]=new node();
		p=p->word[num];
	}
	p->flag++;
}
int find(node *p,char *s)//查找
{
	int len=strlen(s),flag=0;//flag要初始化为0 
	for(int i=0;i<len;i++)
	{
		int num=s[i]-'a';
		if(p->word[num]==NULL)return 0;
		p=p->word[num];
		flag=p->flag;
	}
	return flag;//a为空时返回flag=0; 
}
int main()
{
	root=new node();
	while(gets(ans[letter++]))
	{
		if(strlen(ans[letter-1])==0)break;
		insert(root,ans[letter-1]);
}
	for(int i=0;i<letter;i++)
	{
		int len=strlen(ans[i]),cnt1,cnt2;
		for(int j=0;j<len;j++)
		{
			memset(a,'\0',sizeof(a));
			memset(b,'\0',sizeof(b));
			cnt1=cnt2=0;
			for(int k=0;k<j;k++)a[cnt1++]=ans[i][k];
			for(int k=j;k<len;k++)b[cnt2++]=ans[i][k];
			if(find(root,a)&&find(root,b))
			{
				puts(ans[i]);break;
			}
		}
	}
	return 0;
} 

1.2线段树

#include
using namespace std;
const int N=100005;
int a[N],add[N<<2],ma[N<<2],mb[N<<2],lazy[N<<2],n,m,x,y;
char zf[6];
void PushUp(int rt)
{
	add[rt]=add[rt<<1]+add[rt<<1|1];
	ma[rt]=max(ma[rt<<1],ma[rt<<1|1]);
	mb[rt]=min(mb[rt<<1],mb[rt<<1|1]);
}
void PushDown(int rt)
{
	if(lazy[rt])//如果区间内的数有标记 
	{
		lazy[rt<<1]+=lazy[rt];//整个区间的数都被加过 
		lazy[rt<<1|1]+=lazy[rt];
		ma[rt<<1]+=lazy[rt];//整个区间的最大值都要加 
		ma[rt<<1|1]+=lazy[rt];
		lazy[rt]=0;
	}
}
void Build(int l,int r,int rt)
{
	lazy[rt]=0; 
	if(l==r)
	{
		add[rt]=0;
		ma[rt]=0;
		mb[rt]=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	Build(l,mid,rt<<1);
	Build(mid+1,r,rt<<1|1);
	PushUp(rt);
}
void Update(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		ma[rt]++;
		if(ma[rt]<mb[rt])
		{
			lazy[rt]++;return ;
		}
		else if(l==r&&ma[rt]>=mb[rt])
		{
			add[rt]++;
			mb[rt]+=a[l];//确保每次只加1 
			return ;
		}
	}
	PushDown(rt);
	int mid=(l+r)>>1;
	if(L<=mid)Update(L,R,l,mid,rt<<1);
	if(R>mid)Update(L,R,mid+1,r,rt<<1|1);
	PushUp(rt);
}
int Query(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R)return add[rt];
	PushDown(rt);
	int mid=(l+r)>>1;
	int ans=0;
	if(L<=mid)ans+=Query(L,R,l,mid,rt<<1);
	if(R>mid)ans+=Query(L,R,mid+1,r,rt<<1|1);
	return ans;
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		Build(1,n,1);
		while(m--)
		{
			scanf("%s%d%d",&zf,&x,&y);
			if(zf[0]=='a')Update(x,y,1,n,1);
			else printf("%d\n",Query(x,y,1,n,1));
		}
	}
	return 0;
} 

1.3树状数组

#include
#include
#include
using namespace std;
const int maxn=2e5+10;
int n,c[maxn],u,l,r,id,y;
char q[10];
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int value)
{
	while(x<=n)
	{
		c[x]+=value;
		x+=lowbit(x);
	}
}
int sum(int x)
{
	int sum=0;
	while(x>0)
	{
		sum+=c[x];
		x-=lowbit(x);
	}
	return sum;
}
int main()
{
	int t=0;
	while(~scanf("%d",&n)&&n)
	{
		memset(c,0,sizeof(c));
		for(int i=1;i<=n;i++)
		{
			cin>>u;
			add(i,u);
		}
		if(t)cout<<endl;
		printf("Case %d:\n",++t);
		while(scanf("%s",&q))
		{
			if(q[0]=='E')break;
			if(q[0]=='S')
			{
				cin>>id>>y;
				int w=sum(id)-sum(id-1);
				int value=y-w;
				add(id,value);
			}
			else
			{
				cin>>l>>r;
				int w=sum(r)-sum(l-1);
				cout<<w<<endl;
			}
		}
	}
	return 0;
} 

1.4二叉树建树模板

#include
#include
#include
#include
using namespace std;
typedef struct BiTNode
{
    char data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
void CreateBiTree(BiTree &T)
{
    char ch;
    scanf("%c",&ch);
    if(ch=='#')
        T=NULL;
    else
    {
        T=(BiTree  )malloc(sizeof(BiTNode));
        if(!T)
            exit(-1);
        T->data=ch;
        CreateBiTree(T->lchild);
        CreateBiTree(T->rchild);
    }
}
void InOrderTraversal(BiTree T)
{
    if(T)
    {
        InOrderTraversal(T->lchild);
        printf("%c",T->data);
        InOrderTraversal(T->rchild);
    }
}
int main()
{
    BiTree T;
    CreateBiTree(T);   
    InOrderTraversal(T);   
    return 0;
}

1.5二叉搜索树建树模板

#include 
#include
using namespace std;
struct Node{
    int data;
    Node * left;
    Node * right;
};
typedef Node* Tree;
Tree insert(Tree &BT,int x){//创建树
    if(!BT){
        BT=(Tree)malloc(sizeof(struct Node));
        BT->data=x;
        BT->left=BT->right=NULL;
    }
    else if(x<BT->data)
        insert(BT->left,x);
    else if(x>BT->data)
        insert(BT->right,x);
    return BT;
}
int main(){
    int n,l,x;
    while(cin>>n&&n){
        cin>>l;
        Tree BT=NULL;
        for(int i=0;i<n;i++){
            cin>>x;
            BT=insert(BT,x);
        }
    }
    return 0;
}

1.6树上启发式合并

#include 
using namespace std;
#define lson t[id].l
#define rson t[id].r
typedef long long ll;
const int maxn = 1e5 + 7;
struct Seg{
    int l, r,num;
    ll sum;
}t[maxn * 50];
int n, tot, cor[maxn], rt[maxn];
ll ans[maxn];
vector<int> G[maxn];
void up(int id) {
	// up操作时找左右节点出现次数最多的颜色, 一样多则加起来
    if (t[t[id].l].num > t[t[id].r].num) {
        t[id].num = t[t[id].l].num;
        t[id].sum = t[t[id].l].sum;
    }
    else if (t[t[id].l].num < t[t[id].r].num) {
        t[id].num = t[t[id].r].num;
        t[id].sum = t[t[id].r].sum;
    }
    else{
        t[id].num = t[t[id].l].num;
        t[id].sum = t[t[id].l].sum + t[t[id].r].sum;
    }
}
void modify(int &id, int l, int r, int p) {//id=(t[id].l,t[id].r)
	// 动态开点
    if(!id) id = ++tot;
    if (l == r) {
        t[id].num += 1;
        t[id].sum = l;
        return;
    }
    int mid = l + r >> 1;
    if (p <= mid) modify(lson, l, mid, p);
    else modify(rson, mid + 1, r, p);
    up(id);
}
int merge(int a, int b, int l, int r) {
    if (!a) return b;
 	if (!b) return a;
    if (l == r) {
        t[a].sum = l;
        t[a].num += t[b].num;
        // 合并完后子树的信息可以保存在一棵树上,所以直接合并到a上
        return a;
    }
    int mid = l + r >> 1;
    t[a].l = merge(t[a].l, t[b].l, l, mid);
    t[a].r = merge(t[a].r, t[b].r, mid + 1, r);
    up(a);
    return a;
}
void dfs(int u, int fa) {
    for (auto v : G[u]) {
        if (v == fa) continue;
        dfs(v, u);
        // 对于前n个节点,rt[i] = i
        merge(u, v, 1, n);
    }
    // 将自己本身加到权值线段树里
    modify(u, 1, n, cor[u]);//权 
    ans[u] = t[u].sum;
}
void solve() {
    scanf("%d",&n);
    tot = n;
    for (int i = 1; i <= n; ++i) scanf("%d",&cor[i]);
    for (int i = 1, u, v; i < n; ++i) {
    	scanf("%d %d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, 0);
    for (int i = 1; i <= n; ++i) {
        printf("%lld%c", ans[i], " \n"[i == n]);
    }
}
int main() {
    int _T = 1;
    while (_T--) solve();
    return 0;
}

1.7多叉线段树(dfs序)

#include
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=2e5+200;
int t[N<<2],lazy[N<<2],tot,L[N],R[N],a[N],b[N];
vector<int>e[N];
void build(int l,int r,int rt)
{
    if(l==r)
    {
        t[rt]=b[l];
        return;
    }
    int m=(l+r)/2;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    t[rt]=t[rt<<1]+t[rt<<1|1];
}
void pushdown(int rt,int m)
{
    if(lazy[rt])
    {
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        if(lazy[rt]&1)
        {
            t[rt<<1]=(m-(m>>1))-t[rt<<1];
            t[rt<<1|1]=(m>>1)-t[rt<<1|1];
        }
        lazy[rt]=0;
    }
}
void update(int ql,int qr,int l,int r,int rt)
{
    if(ql==l&&qr==r)
    {
        t[rt]=r-l+1-t[rt];
        lazy[rt]++;
        return;
    }
    pushdown(rt,r-l+1);
int m=(l+r)/2;
    if(qr<=m)update(ql,qr,l,m,rt<<1);
    else if(ql>m)update(ql,qr,m+1,r,rt<<1|1);
    else
    {
        update(ql,m,l,m,rt<<1);
        update(m+1,qr,m+1,r,rt<<1|1);
    }
    t[rt]=t[rt<<1]+t[rt<<1|1];
}
int query(int ql,int qr,int l,int r,int rt)
{
    if(ql==l&&qr==r)
        return t[rt];
    pushdown(rt,r-l+1);
    int m=(l+r)/2;
    if(qr<=m)return query(ql,qr,l,m,rt<<1);
    else if(ql>m)return query(ql,qr,m+1,r,rt<<1|1);
    else
        return query(ql,m,l,m,rt<<1)+query(m+1,qr,m+1,r,rt<<1|1);
    t[rt]=t[rt<<1]+t[rt<<1|1];
}
void dfs(int u)
{
    L[u]=++tot;
    b[tot]=a[u];
    for(auto v:e[u])
        dfs(v);
    R[u]=tot;
}
int main()
{
    int n,x,q;
    char s[10];
    scanf("%d",&n);
    for(int i=2; i<=n; i++)
    {
        scanf("%d",&x);
        e[x].push_back(i);
    }
    for(int i=1; i<=n; i++)scanf("%d",&a[i]);
    dfs(1);
    build(1,n,1);
    scanf("%d",&q);
    while(q--)
    {
        scanf("%s%d",s,&x);
        if(s[0]=='p')
            update(L[x],R[x],1,n,1);
        else
            printf("%d\n",query(L[x],R[x],1,n,1));
    }
    return 0;
}

1.7.1Dfs序代码

void dfs(int x,int pre,int d){//L,R表示一个子树的范围  
    L[x]=++tot;  
    dep[x]=d;  
    for(int i=0;i<e[x].size();i++){  
        int y=e[x][i];  
        if(y==pre)continue;  
        dfs(y,x,d+1);  
    }  
    R[x]=tot;  
}

2.并查集

#include
#include
#include
using namespace std;
const int N = 5e2+5;
typedef long long ll;
// 0代表小于,1代表大于,2代表等于,判别方式(3-x)%3;
// 当每一次出现规则冲突时记录冲突数字,
int f[N],d[N],s[N];
int get(int x)
{
	if(f[x]==x)return x;
	int cur=get(f[x]);
	d[x]=(d[x]+d[f[x]])%3;
	return f[x]=cur;
}
bool join(int p,int q, int fg)
{
	int l=get(p),r=get(q);
	if(l==r)
	{
		if((d[p]+fg)%3==d[q])return true;
			return false;
	}
	f[r]=l;
	d[r]=(fg+3-d[q]+d[p])%3;
	return true;
}
int main()
{
	int n,m,i,j,k;
	char b[2001];
	int a[2001],c[2001];
	while(scanf("%d %d",&n,&m)==2)
	{
		if(m==0)
		{
			if(n==1)printf("Player 0 can be determined to be the judge after 0 lines\n");
			else printf("Can not determine\n");
			continue;
		}
		int flag=0,ans=-1,pos=-1,cnt=0,kk=0;
		for(i=1;i<=m;i++)
		{
			scanf("%d%c%d",&a[i],&b[i],&c[i]);
		}
		for(i=0;i<n;i++)
		{
			for(k=0;k<=n;k++) f[k]=k,d[k]=0;
			cnt=0;
			for(j=1;j<=m;j++)
			{
				if(b[j]=='=') k=0;
				else if(b[j]=='>') k=1;
				else k=2;
				if(a[j]==i||c[j]==i) continue;
				if(!join(a[j],c[j],k))
				{
					cnt++;
					pos=max(pos,j);
					break;
				}
			}
			kk+=(cnt==0);
			if(cnt==0) ans=i;
		}
		if(kk==0)printf("Impossible\n");
		else
		{
			if(kk>1)printf("Can not determine\n");
			else printf("Player %d can be determined to be the judge after %d lines\n",ans,pos);
		}
	}
	return 0;
}

3.动态规划

3.1背包

3.1.101背包

#include
using namespace std;
int main()
{
	int m,n,zz=0;
	cin>>m>>n;
	int dp[m+1],a[n];
	for(int i=0;i<=m;i++)dp[i]=0;
	for(int i=0;i<n;i++)cin>>a[i];
	for(int i=0;i<n;i++)
	{
		for(int j=m;j>=0;j--)
		{
			if(j-a[i]>=0)
			{
				dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
				zz=max(zz,dp[j]);
			}
		}
	}
	cout<<m-zz<<endl;
	return 0;
}

3.1.2多重背包

#include
using namespace std;
int dp[100005],a[1000],b[1000],num[100005];
int main()
{
	int n,m,sum;
	cin>>n>>m;
	while(1)
	{
		if(n==0&&m==0)break;
		for(int i=0;i<=m;i++)dp[i]=0;
		for(int i=0;i<n;i++)cin>>a[i];//面值 
		for(int i=0;i<n;i++)cin>>b[i];//个数 
		sum=0,dp[0]=1;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<=m;j++)num[j]=0;//记录硬币个数 
			for(int j=a[i];j<=m;j++)
			{
				if(!dp[j]&&dp[j-a[i]]&&num[j-a[i]]<b[i])
				{
					num[j]=num[j-a[i]]+1;
					dp[j]=1;
					sum++;
				}
			}
		}
		cout<<sum<<endl;
		cin>>n>>m;
	}
	return 0; 
}

3.1.3二维背包

#include
using namespace std;
int main()
{
	int n,tv,tm,zx=0;
	cin>>n>>tv>>tm;
	int dp[tv+1][tm+1],a[n],b[n],c[n];
	for(int i=0;i<=tv;i++)
	{
		for(int j=0;j<=tm;j++)
		{
			dp[i][j]=0;
		}
	}
	for(int i=0;i<n;i++)cin>>a[i]>>b[i]>>c[i];
	for(int i=0;i<n;i++)
	{
		for(int j=tv;j-a[i]>=0;j--)
		{
			for(int k=tm;k-b[i]>=0;k--)
			{
				dp[j][k]=max(dp[j][k],dp[j-a[i]][k-b[i]]+c[i]);
				zx=max(zx,dp[j][k]);
			}
		}
	}
	cout<<zx<<endl;
	return 0;
}

3.1.4分组背包

#include
#include
#include
using namespace std;
int f[5000],c[5000],w[5000],a[5000][5000],i,j,n,m,s,k,t,p;
int main ()
{
	cin>>n>>m>>t;
	for (i=1; i<=m; i++)
	{
		cin>>w[i]>>c[i]>>p;
		a[p][0]++;
		a[p][a[p][0]]=i;
//		t=max(t,p);//计算组数(在不知道的情况下) 
	}
	for(i=1;i<=t;i++)
	{//组数 
		for(j=n;j>=0;j--)
		{//重量 
			for(k=1;k<=a[i][0];k++)
			{//从每一组第一个数开始递推 
				if(w[a[i][k]]<=j)
				{
				    f[j]=max(f[j],f[j-w[a[i][k]]]+c[a[i][k]]);//如01背包 
			    }
			}
		}
	}
	cout<<f[n];
	return 0; 
}

3.1.5混合背包

#include
using namespace std;
int main()
{
	int t,m,zd=0;
	cin>>t>>m;
	int a[m],b[m],c[m],dp[t+1];
	for(int i=0;i<=t;i++)dp[i]=0;
	for(int i=0;i<m;i++)
	{
		cin>>a[i]>>b[i]>>c[i];
		if(!c[i])c[i]=t;
	}
	for(int i=0;i<m;i++)
	{
		for(int j=t;j>=a[i];j--)
		{
			for(int k=1;k<=c[i];k++)
			{
				if(k*a[i]<=j)
				{
					dp[j]=max(dp[j],dp[j-k*a[i]]+k*b[i]);
					zd=max(zd,dp[j]);
				}
			}
		}
	}
	cout<<zd<<endl;
	return 0;
}

3.1.6完全背包

#include
using namespace std;
int main()
{
	ios::sync_with_stdio(false);
	int t,m,zd=0;
	cin>>t>>m;
	int a[m],b[m],dp[t+1];
	for(int i=0;i<=t;i++)dp[i]=0;
	for(int i=0;i<m;i++)cin>>b[i]>>a[i];
	for(int i=0;i<m;i++)
	{
		for(int j=a[i];j<=t;j++)
		{
			dp[j]=max(dp[j],dp[j-a[i]]+b[i]);
			zd=max(zd,dp[j]);
		}
	}
	cout<<zd<<endl;
	return 0;
}

3.2区间dp

#include
#include
#define INF 0x3f3f3f3f
using namespace std;
long long dp[109][109],sum[109],n,x;
int main()
{
    scanf("%lld",&n);
    for(long long i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        sum[i]=sum[i-1]+x;
    }
    for(long long i=0;i<=n;i++)
        for(long long j=0;j<=n;j++)
			dp[i][j]=0;
    for(long long len=1;len<=n;len++)//区间长度
    {
        for(long long i=1;i+len<=n;i++)//区间起点
        {
            long long j=i+len;//区间终点
        	dp[i][j]=INF;
            for(long long k=i;k<j;k++)//寻找区间中间的点来更新dp值
            {
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
            }
        }
    }
    printf("%lld\n",dp[1][n]);
    for(int i=1;i<=n;i++)
	{
		for(int len=1;len<=n;len++)cout<<dp[i][len]<<" ";
		cout<<endl;
	 } 
    return 0;
}

3.3树形dp

#include
#include
#include
#include
using namespace std;
int n,dp[6005][2],deg[6005],x,y,head,sum;
vector<int>map[6005];
void clear(){
	for(int i=0;i<=6005;i++)if(map[i].size())map[i].clear();
	memset(dp,0,sizeof(dp));memset(deg,0,sizeof(deg));
}
void dfs(int head){
	if(map[head].size()==0)return;
	for(int i=0;i<map[head].size();i++)
	{
		int son=map[head][i];
		dfs(son);//找到最底 
		dp[head][0]+=max(dp[son][0],dp[son][1]);//当前层数加上子层数最大值 
		dp[head][1]+=dp[son][0];//如果选择那子节点只能不选 
	}
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		clear();
		for(int i=1;i<=n;i++)cin>>dp[i][1];
		while(cin>>x>>y)
		{
			if(x==0&&y==0)break;
			deg[x]++;//标记节点 
			map[y].push_back(x);
		}
		for(int i=1;i<=n;i++)
		{
			if(deg[i]==0){head=i;break;}//寻找根节点(入度=0) 
		}
		dfs(head);//根节点dfs 
		sum=max(dp[head][0],dp[head][1]);
		cout<<sum<<endl;
	}
	return 0;
}

3.4数位dp

#include
using namespace std;
typedef long long ll;
ll t,n,a[21],dp[21][10],len,ans;//dp[第i位][数字j] 
void init()
{
	memset(dp,0,sizeof(dp));
	dp[0][0]=1;
	for(int i=1;i<=20;i++)
		for(int j=0;j<=9;j++)
			for(int k=0;k<=9;k++)
				if(!(j==4&&k==9))dp[i][j]+=dp[i-1][k];//如果第i位不为4且第i-1位不为9 
}
ll solve(ll n)
{
	len=ans=0;
	while(n){a[++len]=n%10,n/=10;}
	a[len+1]=0;
	for(int i=len;i>0;i--)
	{
		for(int j=0;j<a[i];j++)if(a[i+1]!=4||j!=9)ans+=dp[i][j];
		if(a[i+1]==4&&a[i]==9)break;
	}
	return ans;
}
int main()
{
	init();
	cin>>t;
	while(t--)
	{
		cin>>n;
		cout<<(n+1)-solve(n+1)<<endl;
	}
	return 0;
} 

3.5最长公共子序列

#include
#include
using namespace std;
const int MAX=1e5; 
int main()
{
	char s[MAX],t[MAX];  
	scanf("%s%s",&s,&t);  
	int x=strlen(s),y=strlen(t),i,j; 
	int dp[x+1][y+1]; 
	memset(dp,0,sizeof(dp));
	cout<<x<<" "<<y<<endl;
	for(i=1;i<=x;i++)  
	{  
	    for(j=1;j<=y;j++)  
	    {
	        if(s[i-1]==t[j-1])  dp[i][j]=dp[i-1][j-1]+1;  
	        else  dp[i][j]=max(dp[i][j-1],dp[i-1][j]);  
	    }         
	}
	 printf("%d\n",dp[i-1][j-1]);  
}

3.6最长上升子序列

#include 
using namespace std;
const int maxn = 103, INF = 0x7f7f7f7f;
int a[maxn], f[maxn],n,ans = -INF;
int main()
{
    scanf("%d", &n);
    for(int i=1; i<=n; i++) {
        scanf("%d", &a[i]);
        f[i] = 1;
    }
    for(int i=1; i<=n; i++)
        for(int j=1; j<i; j++)
            if(a[j] < a[i])
                f[i] = max(f[i], f[j]+1);
    for(int i=1; i<=n; i++) ans = max(ans, f[i]);
    printf("%d\n", ans);
    return 0;
}

4.素数类

4.1Min25筛

#include //求1e10以内的素数和 
using namespace std;
typedef long long ll;
const int N = 1000000 + 10;
int prime[N], id1[N], id2[N], flag[N], ncnt, m;
ll g[N], sum[N], a[N], T, n;
int ID(ll x) {return x <= T ? id1[x] : id2[n / x];}
ll calc(ll x) {return x * (x + 1) / 2 - 1;}
ll init(ll x) {
    T = sqrt(x + 0.5);
    for (int i = 2; i <= T; i++) 
	{
        if (!flag[i]) prime[++ncnt] = i, sum[ncnt] = sum[ncnt - 1] + i;
        for (int j = 1; j <= ncnt && i * prime[j] <= T; j++) 
		{
            flag[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
    for (ll l = 1; l <= x; l = x / (x / l) + 1) 
	{
        a[++m] = x / l;
        if (a[m] <= T) id1[a[m]] = m; else id2[x / a[m]] = m;
        g[m] = calc(a[m]);
    }
    for (int i = 1; i <= ncnt; i++)
        for (int j = 1; j <= m && (ll) prime[i] * prime[i] <= a[j]; j++)
            g[j] = g[j] - (ll) prime[i] * (g[ID(a[j] / prime[i])] - sum[i - 1]);
}
ll solve(ll x) {
    if (x <= 1) return x;
    return n = x, init(n), g[ID(n)];
}
int main() {
    while (1) {
        memset(g, 0, sizeof(g));memset(a, 0, sizeof(a));memset(sum, 0, sizeof(sum));memset(flag, 0, sizeof(flag));
        memset(prime, 0, sizeof(prime));memset(id1, 0, sizeof(id1));memset(id2, 0, sizeof(id2));
        ncnt = m = 0;
        scanf("%lld", &n);printf("%lld\n", solve(n));
    }
}

4.2大于1e9的素数个数模板

#include
using namespace std;
typedef long long ll;
const int N=320005;
ll phi[10005][105], p2[N], ans[N],n;
int len, vis[N];
void init() {
	len = 0;
	for(int i=2; i<N; i++) 
	{
		if(!vis[i]) {
			for(int j=i+i; j<N; j+=i) vis[j]=1;
			p2[len++] = i;
			ans[i] = ans[i-1]+1;
			continue;
		}
		ans[i] = ans[i-1];
	}
	for(int i=0; i<=10000; i++) {
		phi[i][0] = (ll)i;
		for(int j=1; j<=100; j++) phi[i][j] = phi[i][j-1] - phi[i/p2[j-1]][j-1];
	}
}
ll solve_phi(ll m, ll n) {
	if(!n) return m;
	if(p2[n - 1] >= m) return 1;
	if(m<=10000 && n<=100) return phi[m][n];
	return solve_phi(m, n-1) - solve_phi(m/p2[n-1], n-1);
}
ll solve_p2(ll m) {
	if(m < (ll)N) return ans[m];
	ll y = (int)cbrt(m*1.0);
	ll n = ans[y];
	ll sum = solve_phi(m, n) + n -1;
	for(ll i=n; p2[i]*p2[i]<=m; i++)sum = sum - solve_p2(m/p2[i])+solve_p2(p2[i])-1;	
	return sum;
}
int main(){
    init();
    scanf("%lld", &n);
    printf("%lld\n",solve_p2(n));
    return 0;
}

5.大数据

5.1大数据处理(c++)

#include
#include
static const int LEN=1004;
int a[LEN],b[LEN],c[LEN],d[LEN];
void clear(int a[]) {for(int i=0;i<LEN;++i)a[i]=0;}
void read(int a[]) 
{
    static char s[LEN + 1];
    scanf("%s",s);
    clear(a);
    int len=strlen(s);
    for (int i=0;i<len;++i)a[len-i-1]=s[i]-'0';
}
void print(int a[]) 
{
    int i;
    for(i=LEN-1;i>=1;--i)if(a[i]!=0)break;
    for(;i>=0;--i)putchar(a[i]+'0');
    putchar('\n');
}
void mul(int a[],int b[],int c[]) 
{
    clear(c);
    for(int i=0;i<LEN-1;++i) 
	{
        for(int j=0;j<=i;++j)c[i]+=a[j]*b[i-j];
        if(c[i]>=10) 
		{
            c[i+1]+=c[i]/10;
            c[i]%=10;
        }
    }
}
int main() 
{
    read(a);
    read(b);
    mul(a,b,c);
    print(c);
    return 0;
}

5.2大数据处理(java)

import java.math.BigInteger;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        BigInteger s=BigInteger.valueOf(4);
        Scanner cin=new Scanner(System.in);
        int T=cin.nextInt();
        for(int k=0;k<T;++k)
        {
            BigInteger si=BigInteger.valueOf(4);
            BigInteger two=BigInteger.valueOf(14);
            BigInteger t=cin.nextBigInteger();//输入n 
            if(t.compareTo(si)<=0) {
                System.out.println(si);
                continue;
            }
            if(t.compareTo(two)<=0) {
                System.out.println(two);
                continue;
            }
            while(true)
            {
                BigInteger temp=two;
                two=two.multiply(s).subtract(si);//f[i]*4-f[i-1] 
                si=temp;
                if(t.compareTo(two)<=0) {//t>n 
                    System.out.println(two);
                    break;
                }
            }
        }
    }
}

5.3Java大数算法

5.3.1四则运算

package BigInteger;
import java.util.*;
import java.math.*;
public class Main {
    public static void main(String args[]) {
        Scanner cin = new Scanner(System.in);
        BigInteger a , b;
        a=cin.nextBigInteger();
        b=cin.nextBigInteger();
        BigInteger ans_add,ans_sub,ans_mul,ans_div,ans_mod;
        ans_add = a.add(b); //a+b
        ans_sub = a.subtract(b); //a-b
        ans_mul = a.multiply(b); //a*b
        ans_div = a.divide(b); //a/b
        ans_mod = a.mod(b); //a%b
        System.out.println("a + b = "+ans_add);
        System.out.println("a - b = "+ans_sub);
        System.out.println("a * b = "+ans_mul);
        System.out.println("a / b = "+ans_div);
        System.out.println("a % b = "+ans_mod);
    }
}

//Java大数多余后导0去除
String str;
str=ans.stripTrailingZeros().toPlainString();//去除所有后导0,并且转化成字符型
//ans为大浮点数运算后得到的答案
//如果小数点前面的0也需要去掉,那么输出的时候处理一下即可:
if(str.charAt(0)=='0')
        System.out.println(str.substring(1));
else
        System.out.println(str);

5.3.2Java大数阶乘

package BigInteger;
import java.util.*;
import java.math.*;
public class Main {
    public static BigInteger factorial(BigInteger n){  
            BigInteger bd1 = new BigInteger("1");
            BigInteger bd2 = new BigInteger("2");
            BigInteger result = bd1;
            while(n.compareTo(bd1) > 0){
                    result = result.multiply(n);  
                    n = n.subtract(bd1); 
            }   
            return result;   
        }  
    public static void main(String args[]) {
        Scanner cin = new Scanner(System.in);
        BigInteger n;
        n=cin.nextBigInteger();
        BigInteger ans;
        ans = factorial(n);
        System.out.println("n的阶乘为: "+ans);
    }
}

6.逆序数

#include//树状数组 
#define maxn 50010
#include
#include
using namespace std;
int n,m,a,i,j,b[maxn],c[maxn];
struct node
{
	int num,id;
}s[maxn];
int lowbit(int k){return k&(-k);}
int cmp(struct node a,struct node b){return a.num<b.num;}
int sum(int x){//求前x项的和
	int he=0;
	while(x){
		he+=c[x];
		x-=lowbit(x);
	}
	return he;
}
void add(int x ,int num){//更新树
	while(x<maxn){
		c[x]+=num;
		x=x+lowbit(x);
	}
}
int main(){
	while(scanf("%d",&n)!=EOF){
		for(i=1;i<=n;i++){scanf("%d",&s[i].num);s[i].id=i;}
		sort(s+1,s+n+1,cmp);
		b[s[1].id]=1;//b数组为对应原数组数据的大小[1,n] 
		for(i=2;i<=n;i++){
			if(s[i].num==s[i-1].num)b[s[i].id]=b[s[i-1].id];
			else b[s[i].id]=i;	
		}
		long long int ans=0;//注意极端情况下的逆序数总和会爆int
		for(i=1;i<=n;i++){
			add(b[i],1);//更新树
			ans+=sum(n)-sum(b[i]);		}
		printf("%I64d\n",ans);
	}
}

7.STL类

7.1常用STL库

点此跳转常用STL库

7.2容器set

#include
using namespace std;
char a[300],b[300];
set<string>s;
int main()
{
	while(scanf("%s",a)!=EOF)
	{
		int len=strlen(a);
		for(int i=0;i<len;i++)
		{
			if(isalpha(a[i]))a[i]=tolower(a[i]);//#include  1.isalpha检测是否为字母  2.tolower将大写转化为小写 
			else a[i]=' ';
		}
		string ab=(string)a;
		stringstream ss(ab);//string字符串拼接 
		while(ss>>b)s.insert(b);
	}
	for(set<string>::iterator p=s.begin();p!=s.end();p++) cout<<*p<<endl;
	return 0;
}

8.数学模板

8.1卢卡斯定理求组合数模板

#include 
#include 
using namespace std;
typedef long long LL;
int qmi(int a, int k, int p){
    int res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}
int C(int a, int b, int p){
    if (b > a) return 0;
    int res = 1;
    for (int i = 1, j = a; i <= b; i ++, j -- )
    {
        res = (LL)res * j % p;
        res = (LL)res * qmi(i, p - 2, p) % p;
    }
    return res;
}
int lucas(LL a, LL b, int p){
    if (a < p && b < p) return C(a, b, p);
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
int main(){
    int n;
    cin >> n;
    while (n -- ){
        LL a, b;
        int p=1000000007;
        cin >> a >> b ;
        if(a<b){
         int t=a;a=b;b=t;
  		}
        cout << lucas(a, b, p) << endl;
    }
    return 0;
}

8.2逆元法求组合数模板

#include 
#include 
using namespace std;
typedef long long LL;
const int N = 100010, mod = 1e9 + 7;
int fact[N], infact[N];
int qmi(int a, int k, int p)
{
    int res = 1;
    while (k)
    {
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}
int main()
{
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i ++ )
    {
        fact[i] = (LL)fact[i - 1] * i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }
    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        if(a<b)
        {
         int t=a;a=b;b=t;}
        printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
    }
    return 0;
}

9.图

9.1迪杰斯特拉/单源最短路模板

#include
#include
const int maxn=20005;
using namespace std;
int mp[maxn][maxn],dis[maxn],vis[maxn],n,m,first,x,y,cnt; 
void Dijkstra(int first){
	for(int i=0;i<n;i++){
		dis[i]=mp[first][i];//先把起始点到其他各点的距离存下来 
	}
	dis[first]=0;vis[first]=1;//vis已经遍历过了 
	for(int i=0;i<n;i++){
		int Min=0x3f,pos;
		for(int j=0;j<n;j++)
		{//找到还没有作为起点的最小位置 
			if(!vis[j]&&Min>dis[j])
			{
				Min=dis[j],pos=j;
			}
		}
		vis[pos]=1;//标记已经作为起始点了 
		for(int j=0;j<n;j++)//以刚才那个点作为起始点,更新一遍dis数组 
		{
			dis[j]=min(dis[j],dis[pos]+mp[pos][j]);
		}
	}
}
int main(){
    scanf("%d%d%d",&n,&m,&first);
    memset(mp,0x3f,sizeof(mp));
	memset(dis,0,sizeof(dis));
	memset(vis,0,sizeof(vis));
    for(int i=0;i<m;i++){
    	scanf("%d%d%d",&x,&y,&cnt);
    	mp[x][y]=mp[y][x]=cnt;
	}
	Dijkstra(first);
	for(int i=0;i<n;i++){
		printf("%d ——> %d\n",i,dis[i]);
	}
    return 0;
}

9.2搜索模板

9.2.1DFS深度优先搜索模板

#include
#include
using namespace std;
char map[25][25];//地图 
int pd[25][25];//路径 
int yidong[4][2]={{1,0},{-1,0},{0,1},{0,-1}};//移动下上右左
int sum,n,m;
bool bj(int x,int y)
{
	if(x<1||x>n||y<1||y>m)//判断边界 
		return false;
	if(map[x][y]=='#')//判断墙体 
		return false;
	if(pd[x][y])//判断是否走过 
		return false;
	return true; 
}
void dfs(int x,int y)
{
	int i,px,py;
	if(bj(x,y))//判断是否能走 
	{
		pd[x][y]=1;//标记走过 
		sum++;//计数 
		for (i=0;i<4;i++)//核心代码(移动) 
		{
			px=x+yidong[i][0];
			py=y+yidong[i][1];
			dfs(px,py);
		}
	}
	else
		return;
}
int main()
{
	int i,j,x,y;
	while(scanf("%d %d",&m,&n),m+n)
	{
		memset(pd,0,sizeof pd);//iostream初始化 
		for(i=1;i<=n;i++)
		{
			scanf("%s",map[i]+1);//map[1][1]开始 
		}
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
			{
				if(map[i][j]=='@')//标记初始点 
				{
					x=i;y=j;
				}
			}
		}
		sum=0;
		dfs(x,y);
		cout<<sum<<endl;
	}
}

9.2.2BFS广度优先搜索模板

#include
using namespace std;
int n,m,a[105][105],ans[105][105],st1,st2,ed1,ed2,yd[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node{
	int x,y;
};
bool pd(int x,int y)
{
	if(x<1||x>n||y<1||y>m)return false;
	if(a[x][y]==1)return false;
	if(ans[x][y]!=0)return false;
	return true;
}
void bfs(int x,int y)
{
	queue<node>q;
	node next,last;
	next.x=x,next.y=y;
	q.push(next);
	while(!q.empty())
	{
		last=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			next.x=last.x+yd[i][0];
			next.y=last.y+yd[i][1];
			if(pd(next.x,next.y))
			{
				ans[next.x][next.y]=ans[last.x][last.y]+1;
				q.push(next);
			}
		}
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>a[i][j];
	cin>>st1>>st2>>ed1>>ed2;
	bfs(st1,st2);
	cout<<ans[ed1][ed2]+1<<endl;
	return 0;	
} 

本文不定时更新,觉得有用可以点击收藏。

你可能感兴趣的:(c++,ACM,STL,算法,c++,数据结构)