常用算法模板
快速幂
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;
}
卢卡斯定理(最快)
#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;
}
逆序数(树状数组)
#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]);
模拟退火:
#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;
}
先就这么多,慢慢更新。。。
浙公网安备 33010602011771号