Java教程

常用算法模板

本文主要是介绍常用算法模板,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

快速幂

LL pow(LL a, LL n, LL p)    //快速幂 a^n % p
{
    LL ans = 1;
    while(n)
    {
        if(n & 1) ans = ans * a % p;          //若不取模就去掉p
        a = a * a % p;
        n >>= 1;
    }
    return ans;
}

 

线性质数筛

const int N=1e9+5;
int a[N],b[N];
void prime(int n)
{
	int k=1;
	for(int i=2;i<=n;i++)
	{
		if(!a[i])
		{
			b[k++]=i;
		}
		for(int j=1;j<=k&&i*b[j]<=n;j++)
		{
			a[i*b[j]]=1;
			if(i%b[j]==0)
			break;
		}
	}
}

 

组合数

//简易版
void comb(int n)
{
	c[1][1]=1;
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=100;j++)
		{
			if(i==j)
			c[i][j]=1;
			else if(j==1)
			c[i][j]=i;
			else
			c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
		}
	}
}

//gcd版
typedef long long LL;
LL gcd(LL a,LL b)
{
	return b==0 ? a : gcd(b,a%b);
}
LL comb(LL n,LL k)
{
	if(k*2>=n)
	k=n-k;
	LL a=1,b=1;
	for(LL i=1;i<=k;i++)
	{
		a=a*(n-i+1),b*=i;
		LL g=gcd(a,b);
		a/=g,b/=g;
	}
	return a/b;
}

 

卢卡斯定理(最快)

【模板】卢卡斯定理 [P3807]

#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+3;
int n,m,P,T,jc[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline int mi(Re x,Re k){
    Re s=1;
    while(k){
        if(k&1)s=(LL)s*x%P;
        x=(LL)x*x%P,k>>=1;
    }
    return s;
}
inline int inv(Re x){return mi(x,P-2);}
inline int C(Re m,Re n){
    return m>n?0:(LL)jc[n]*inv(jc[m])%P*inv(jc[n-m])%P;
}
inline int Lucas(Re m,Re n){
    return m==0?1:(LL)Lucas(m/P,n/P)*C(m%P,n%P)%P;
}
int main(){
//    freopen("123.txt","r",stdin);
    in(T);
    while(T--){
        in(n),in(m),in(P),jc[0]=1;
        for(Re i=1;i<=P-1;++i)jc[i]=(LL)jc[i-1]*i%P;
        printf("%d\n",Lucas(n,n+m));
    }
}

 

二分

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

 

逆序数(树状数组)

逆序对 [P1908]

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=500050;
int n;
long long c[N];      //c[n]表示a[1~n]的和,a数组省略
struct node
{
    int val,pos;
}a[500005];

int lowbit(int x)       //求2^k
{
    return x & -x;
}

long long getsum(int n)   //区间查询,求a[1~n]的和
{
    long long res = 0;
    while(n>0)
    {
        res+=c[n];
        n=n-lowbit(n);
    }
    return res;
}

int change(int x)  //单点更新,将c[x]的值加1
{
     while(x<=n)
     {
         c[x]++;
         x+=lowbit(x);
     }
}

bool cmp(node a,node b)         //包含相同数
{
    if(a.val!=b.val)
        return a.val>b.val;
    return a.pos>b.pos;
}

int main()
{
    std::ios::sync_with_stdio(false);
    while(cin>>n)
    {
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++)
        {
            cin>>a[i].val;
            a[i].pos=i;
        }
        sort(a+1,a+n+1,cmp);
        long long cnt=0;
        for(int i=1;i<=n;i++)
        {
            change(a[i].pos);                     //修改最大数位置的值
            cnt+=getsum(a[i].pos-1);     //最大数位置之前的所有位置和,即区间求和,可知比当前数小的数有多少个
        }
        cout<<cnt<<endl;
    }
    return 0;
}

 

最长上升子序列【LIS】

int main(){
	int n;
	while(cin>>n){
		for(int i=1;i<=n;i++){
			scanf("%d",&num[i]);
		}
		
		dp[0]=inf;
		int cnt=0;
		for(int i=1;i<=n;i++){
			if(dp[cnt]>=num[i]){
				cnt++;
				dp[cnt]=num[i];
			}
			else {
				int t=upper_bound(dp+1,dp+cnt+1,num[i],cmp)-dp;//最长非递增子序列 (可重复) 
				dp[t]=num[i];
			}
		}
		cout<<cnt<<endl;
		
		dp[0]=0;
		cnt=0;
		for(int i=1;i<=n;i++){
			if(dp[cnt]<num[i]){
				cnt++;
				dp[cnt]=num[i];
			}
			else {
				int t=lower_bound(dp+1,dp+cnt+1,num[i])-dp;//最长严格递增子序列 
				dp[t]=num[i];
			}
		}
		cout<<cnt<<endl;
	}
	return 0;
}

 

最长公共子序列【LCS】

    int l1,l2;
    char s1[N],s2[N];
    scanf("%d%d",&l1,&l2);
    scanf("%s%s",s1,s2);
    for(int i=0;i<l1;i++)
        for(int j=0;j<l2;j++)
            if(s1[i]==s2[j])
                dp[i+1][j+1]=dp[i][j]+1;
            else
                dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
     printf("%d\n",tmp[l1][l2]);

 

先就这么多,慢慢更新。。。

 

这篇关于常用算法模板的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!