• 博客园Logo
  • 会员
  • 周边
  • 捐助
  • 新闻
  • 博问
  • 闪存
  • 赞助商
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 简洁模式 ... 退出登录
    注册 登录
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  阅读(85)  评论(0)  编辑  收藏  举报
会员力量,点亮园子希望
刷新页面返回顶部
Copyright © 2024 wxk1213
Powered by .NET 8.0 on Kubernetes