• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
24
博客园    首页    新随笔    联系   管理    订阅  订阅

常用算法模板

快速幂

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]);

 

模拟退火:

UVA10228

#include<bits/stdc++.h>
#define down 0.996
using namespace std;

int tt,n;
double ansx,ansy,answ;
struct edg
{
	int x,y;
}a[200];

double energy(double x,double y)
{
	double s=0;
	for(int i=1;i<=n;i++)
	{
		s+=sqrt((x-a[i].x)*(x-a[i].x)+(y-a[i].y)*(y-a[i].y));
	}
	return s;
}

void fire()
{
	double t=3000;
	while(t>1e-15)
	{
      //生成[-T*RAND_MAX,T*RAND_MAX)的随机变动范围(rand():[0,RAND_MAX))
       //rand()一个随机数,RAND_MAX随机范围内最大值
		double ex=ansx+(rand()*2-RAND_MAX)*t;
		double ey=ansy+(rand()*2-RAND_MAX)*t;
		double ew=energy(ex,ey);
		double dw=ew-answ;
		if(dw<0)
		{
			ansx=ex,ansy=ey,answ=ew;
		}
		else if(exp(-dw/t)*RAND_MAX>rand())
		{
			ansx=ex,ansy=ey;
		}
		t*=down;
	}
}

void solve()
{
	fire();
	fire();
	fire();
	fire();
}

int main()
{
	cin>>tt;
	while(tt--)
	{
		cin>>n;
		ansx=0,ansy=0;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i].x>>a[i].y;
			ansx+=a[i].x,ansy+=a[i].y;
		}
		ansx/=n,ansy/=n;
		answ=energy(ansx,ansy);
		solve();
		printf("%.0lf\n",answ);
		if(tt) printf("\n");
	}
	return 0;
}

 

 

 最短路(dij)

#include <bits/stdc++.h>
using namespace std;
const int N=200005;
const int M=400005;
int n,m,t,dis[N];
int idx,fir[M],nex[M],v[M],w[M];
bool vis[N];
struct edg
{
	int x,d;
	bool operator<(const edg &c)const{
	    return d>c.d;
	}
};

void add(int x,int y,int z)
{
	w[idx]=z;
	v[idx]=y;
	nex[idx]=fir[x];
	fir[x]=idx++;
 } 

void dij(int f)
{
	memset(dis,0x3f,sizeof dis);
	priority_queue<edg> q;
	q.push({f,0});
	dis[f]=0;
	while(q.size())
	{
		edg p=q.top();
		q.pop();
	//	if(vis[p.x]) continue;
	//	vis[p.x]=1;
		if(p.d>dis[p.x]) continue;
		for(int i=fir[p.x];~i;i=nex[i])
		{
			int j=v[i];
			if(dis[j]>p.d+w[i])
			{
				dis[j]=p.d+w[i];
				q.push({j,dis[j]});
			 } 
		}
	}
}

int main()
{
	memset(fir,-1,sizeof fir);
	cin>>n>>m>>t;
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		add(x,y,z);
	}
	dij(t);
	for(int i=1;i<=n;i++)
	cout<<dis[i]<<" ";
	return 0;
}

 

线段树

#include<bits/stdc++.h>
using namespace std;
int tree[100005];
int a[]={1,3,5,7,9,11};
int size=6;

void build(int node,int start,int end)
{
	if(start==end)
	{
		tree[node]=a[start];
	}
	else
	{
		int mid=(start+end)/2;
		int left=node*2+1;
		int right=node*2+2;
		build(left,start,mid);
		build(right,mid+1,end);
		tree[node]=tree[left]+tree[right];
	}
}

void update(int node, int start, int end, int x, int val) 
{
	if(start==end)
	{
		a[x]=val;
		tree[node]=val;
	}
	else
	{
		int mid=(start+end)/2;
		int left=node*2+1;
		int right=node*2+2;
		if(x>=start&&x<=mid)
		update(left,start,mid,x,val);
		else
		update(right,mid+1,end,x,val);
		tree[node]=tree[left]+tree[right];
	}
}

int query(int node, int start, int end, int l, int r)
{
	if(l>end||r<start)
	return 0;
	else if(l<=start&&r>=end)
	return tree[node];
	else
	{
		int mid=(start+end)/2;
		int left=node*2+1;
		int right=node*2+2;
		int sum_left=query(left,start,mid,l,r);
		int sum_right=query(right,mid+1,end,l,r);
		return sum_left+sum_right;
	}
}

int query_min(int node, int start, int end, int l, int r)
{
	if(l==start&&r==end)
	return tree[node];
	else
	{
		int mid=(start+end)/2;
		int left=node*2;
		int right=node*2+1;
		if(r<=mid)
		return query(left,start,mid,l,r);
		else if(l>mid)
		return query(right,mid+1,end,l,r);
		else
		return min(query(left,start,mid,l,mid),query(right,mid+1,end,mid+1,r)); 
	}
}

int main()
{
	build(0,0,5);
	for(int i=0;i<=14;i++)
	cout<<tree[i]<<" ";
	cout<<endl;
	
	update(0,0,5,4,6);
	for(int i=0;i<=14;i++)
	cout<<tree[i]<<" ";
	cout<<endl;
	
	cout<<query(0,0,5,2,5);
	return 0;
 }

 

区间修改:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
ll a[100005],tree[400005],vis[400005];

void push_up(int node)
{
	tree[node]=tree[node<<1]+tree[node<<1|1];
}

void build(int node, int l, int r)
{
	if(l==r)
	{
		tree[node]=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(node<<1,l,mid);
	build(node<<1|1,mid+1,r);
	push_up(node);
}

void push_down(int node,int l,int r)
{
	if(vis[node])
	{
		int mid=(l+r)>>1;
		int lazy=vis[node];
		tree[node<<1]+=(mid-l+1)*lazy;
		tree[node<<1|1]+=(r-mid)*lazy;
		vis[node<<1]+=lazy;
		vis[node<<1|1]+=lazy;
		vis[node]=0;
	}
}

ll query(int node, int l, int r, int start, int end)
{
	if(l>=start&&r<=end)
	{
		return tree[node];
	}
	push_down(node,l,r);
	int mid=(l+r)>>1;
	ll sum=0;
	if(start<=mid) sum+=query(node<<1,l,mid,start,end);
	if(end>=mid+1) sum+=query(node<<1|1,mid+1,r,start,end);
	return sum;
}

void update(int node, int l, int r, int start, int end, int date)
{
	if(l>=start&&r<=end)
	{
		tree[node]+=(r-l+1)*date;
		vis[node]+=date;
		return ;
	}
	push_down(node,l,r);
	int mid=(l+r)>>1;
	if(start<=mid) update(node<<1,l,mid,start,end,date);
	if(end>=mid+1) update(node<<1|1,mid+1,r,start,end,date);
	push_up(node);
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	build(1,1,n);
	while(m--)
	{
		int c,x,y,z;
		cin>>c;
		if(c==1)
		{
			cin>>x>>y>>z;
			update(1,1,n,x,y,z);
		}
		else
		{
			cin>>x>>y;
			cout<<query(1,1,n,x,y)<<endl;
		}
	}
	return 0;
}

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;//题目描述n

struct node {
    int l,r;//节点表示范围l~r
    ll sum,lazy;//sum节点属性,lazy跟新延迟标记
    inline int len() {
        return r-l+1;
    }
    inline void update(int val) {
        lazy+=val;
        sum+=1LL*len()*val;//1LL防止int溢出,转为ll
    }
}tr[maxn*4];
int a[maxn];

//回溯跟新
void push_up(int id) {
    tr[id].sum=tr[id<<1].sum+tr[id<<1|1].sum;
}
//下放标记

void push_down(int id) {
    ll lazy=tr[id].lazy;
    if(lazy==0) return;
    tr[id<<1].update(lazy);
    tr[id<<1|1].update(lazy);
    tr[id].lazy=0;
}
//建立线段树

void build(int id, int l, int r) {
    tr[id].l=l;tr[id].r=r;
    tr[id].lazy=tr[id].sum=0;
    if(l==r) {
        tr[id].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(id<<1,l,mid);
    build(id<<1|1,mid+1,r);
    push_up(id);//建立的过程中顺带区间统计
}
//跟新线段树

void update(int id, int l, int r ,int val) {
    if(tr[id].l==l&&tr[id].r==r) {
        tr[id].update(val);
        return;
    }
    push_down(id);
    int mid=(tr[id].l+tr[id].r)>>1;
    if(r<=mid) update(id<<1,l,r,val);
    else if(l>mid) update(id<<1|1,l,r,val);
    else {
        update(id<<1,l,mid,val);
        update(id<<1|1,mid+1,r,val);
    }
    push_up(id);
}

ll query(int id, int l, int r) {
    if(tr[id].l==l&&tr[id].r==r) {
        return tr[id].sum;
    }
    push_down(id);
    int mid=(tr[id].l+tr[id].r)>>1;
    if(r<=mid) return query(id<<1,l,r);
    else if(l>mid) return query(id<<1|1,l,r);
    else return query(id<<1,l,mid)+query(id<<1|1,mid+1,r);
}

int main() {
    int n,q,o;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<=q;++i) {
        scanf("%d",&o);
        if(o==2)
		{
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(1,l,r));
        } 
		else
		{
            int l,r,val;
            scanf("%d%d%d",&l,&r,&val);
            update(1,l,r,val);
        }
    }
    return 0;
}

 

主席树:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,a[N],root[N],cnt;
vector<int> q;

struct edg{
	int l,r,sum;
}T[N*40];

int getid(int x){
	return lower_bound(q.begin(),q.end(),x)-q.begin()+1;
}

void update(int l, int r, int &x, int y, int pos){
	T[++cnt]=T[y],T[cnt].sum++,x=cnt;
	if(l==r) return ;
	int mid=l+r>>1;
	if(mid>=pos) update(l,mid,T[x].l,T[y].l,pos);
	else update(mid+1,r,T[x].r,T[y].r,pos);
}

int query(int l, int r, int x, int y, int k){
	if(l==r) return l;
	int mid=l+r>>1;
	int sum= T[T[y].l].sum - T[T[x].l].sum;
	if(sum>=k) return query(l,mid,T[x].l,T[y].l,k);
	else return query(mid+1,r,T[x].r,T[y].r,k-sum);
}

int main() {
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i]; q.push_back(a[i]);
	}
	sort(q.begin(),q.end());
	q.erase(unique(q.begin(),q.end()),q.end());
	for(int i=1;i<=n;i++){
		update(1,n,root[i],root[i-1],getid(a[i]));
	}
	while(m--){
		int x,y,z;
		cin>>x>>y>>z;
		cout<<q[query(1,n,root[x-1],root[y],z)-1]<<endl;
	}
	
	return 0;
}

 

 

 

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

 

posted @ 2021-12-01 01:24  wxk1213  阅读(108)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3