笔记

Day 1

The First Class

蒟蒻太蒟了,所以前面没记笔记。

前面笔记推荐czh的:https://www.cnblogs.com/CheZiHe929/p/17538291.html

四.栈(stack)

核心函数同queue,除front变top。

```cpp

求区间最大值
 int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
    cin>>a[i];
    }
    for(int i=1;i<=n-k+1;i++){
    int minv=a[i],maxv=a[i];
        for(int j=0;j<=k;i++){//枚举区间左端点
            minv=min(minv,a[i+j]);
            maxv=max(maxv,a[i+j]);
        }
        cout<<maxv-minv<<'\n';
    }
 return 0;   
}

五。单调队列

对,单调队列的特性就是这四个zhx写的字。(zhx:是笔的问题,我的字很好看的)

求区间最小值
 int a[1919810],n,k;
struct queueue{
	int z[1919810]={0};
	int head=1;
	int tail=0;
	void push(int x)
        while(head<=tail&&a[x]<=a[z[tail]])tail--;
		a[++tail]=x;
	}
	void pop(){
		head++;
	}
	int top(){
		return z[head];
	}
	int back(){
		return z[tail];
	}
	int size(){
		return tail-head+1;
	}
};
queueue q;
int main(){
cin>>n>>k;
    for(int i=1;i<=n;i++){
    cin>>a[i];
    }
    for(int i=1;i<=k;i++){
q.push(i);
    }
    cout<<q.top()<<endl;
    for(int i=2;i<=n-k+1;i++){
    q.push(i+k-1);//右边多一个数
        if(q.top()==i-1)q.pop();//左边扔一个数
        cout<<a[q.top()]<<endl;//第i个区间的答案
    }
    return 0;
}

B3616、3614、P1886例题

六、优先队列(堆,priority_queue)

大根堆求最大值,小根堆求最小值。

大根堆:priority_queue<int>q;(引用queue库)

小根堆:priority_queue<int,vector<int>,greater<int> >q;(引用queue,functional,vector库)

#include<queue>
#include<functional>
#include<vector>
#include<iostream>
using namespace std;
priority_queue<int,vector<int>,greater<int> >heap;
int main(){
heap.push(233);//向堆里扔一个数,O(logn)
    heap.pop();//扔掉最小值,O(logn)
    heap.top();//询问最大值 O(1)
    heap.size();//询问堆的大小 O(1)
    return 0;
}

log过程:

《有点长》

我们要用二叉树来实现堆。

二叉树就是一个节点上有一个左儿子和一个右儿子(子节点)。

父节点的值不能小于子节点。

int main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++){
     priority_queue<int>heap_l;
        priority_queue<int,vector<int>,greater<int> >heap_r;
        heap_l.push(a[l]);
        cout<<l~l的中位数为a[l]<<'\n';
        if(a[r]>median)heap_r.push(a[r]);
    }
return 0;
}
手写queue
 struct heap{
    int n;
    int top(){//最大值
        return a[1];
    }
    int size(){//大小
      return n;
    }
    void push(int x){//加入一个数
n++;
        a[n]=x;
        int p=n;
        while(p!=1){
         int f=p/2;
            if(a[f]<a[p]){
         swap(a[f],a[p]);
                p=f;
            }
            else break;
        }
    }
    void pop(){//删除最大值
        a[1]=a[n];
        n--;
        int p=1;
        while(p*2<=n){
       int pp=p*2;//左儿子
            if(pp+1<=n && a[pp+1]>a[pp])pp=pp+1;//pp指向更大的
            if(a[p]<a[pp]){
             swap(a[p],a[pp]);
                p=pp;
            }
            else break;
        }
    }

七.映射(map)

#include<map>
using namespace std;
map<int,int>a;//下标类型
//map<node,node>a;(重载运算符)
//map<string,int>a;(a["kkksc03"]=1)
int main(){
    a[1]=2;//log
    a[2147483647]=0;//log
    a[-2333]=0;//log
    return 0;
}

The second class

算法篇

库:algorithm

一.函数

//对单体的算法
min(a,b);//求最小值
max(a,b);//求最大值
swap(a,b;)//交换两个变量的数值
min(a,min(b,min(c,min(d,e)))//大min套小min(max也可以)
  //  要求数据类型一致
    //对数组的算法
    sort(a+1,a+n+1);//把a[1]~a[n]从小到大排序
    quick_sort(a+1,a+n+1);//快排
    merge_sort(a+1,a+n+1);//归并
    heap_sort(a+1,a+n+1);//堆
    sort(a+1,a+n+1,cmp);//自定义
    bool cmp(int a,int b){
return a>b;
    }
    reverse(a+1,a+n+1)//翻转a[1]-a[n]
    unique(a+1,a+n+1);//把a[1]-a[n]去重
    //如果去重后有x个数,会返回a+x+1
    random_shuffle(a+1,a+n+1);//把a[1]~a[n]随机打乱

二.归并排序

void merge_sort(int l,int r){//对a[l]~a[r]排序
if(l==r)return;
    int m=(l+r)/2;
    merge_sort(1,m);//左部分排序
    merge_sort(m+1,r);//右部分排序
    int pl=l;//左边第一个数的下标
    int pr=m+1;//右边第一个数的下标
    for(int i=l;i<=r;i++){
        if(pl>m)b[i]=a[pr],pr++;
        else if(pr>r)b[i]=a[pl],pl++;
if(a[pl]<a[pr])b[i]=a[pl],pl++;
        else b[i]=a[pr],pr++;
    }
    for(int i=l;i<=r;i++)a[i]=b[i];
}
int main(){
   cin>>n;
    for(int i=1;i<=n;i++){
   cin>>a[i];
    }
    merge_sort(1,n);
    for(int i=1;i<=n;i++){
cout<<a[i];
    }
    return 0;
}

思想是分治。

O(nlogn)

三.逆序对

和归并排序差不多

三种情况:在左,在右,一半左一半右

 

long long merge_sort(int l,int r){//对a[l]~a[r]排序
if(l==r)return 0;
    int m=(l+r)/2;
   ans+=merge_sort(1,m);//左部分排序
    ans+=merge_sort(m+1,r);//右部分排序
    int pl=l;//左边第一个数的下标
    int pr=m+1;//右边第一个数的下标
    for(int i=l;i<=r;i++){
        if(pl>m)b[i]=a[pr],pr++;
        else if(pr>r)b[i]=a[pl],pl++;
if(a[pl]<a[pr])b[i]=a[pl],pl++;
        else b[i]=a[pr],pr++,ans+=m-pl+1;
    }
    for(int i=l;i<=r;i++)a[i]=b[i];
    return ans;
}
int main(){
   cin>>n;
    for(int i=1;i<=n;i++){
   cin>>a[i];
    }
    long long ans=merge_sort(1,n);
    for(int i=1;i<=n;i++){
cout<<ans;
    }
    return 0;
}

四.前缀和

int main(){
 cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
    cin>>m;
    for(int i=1;i<=m;i++){
int l,r;
        cin>>l>>r;
        cout<<sum[r]-sum[l-1];
        putchar('\n');
    }
}

五.差分

前缀和从l开始都要改掉

把l~r加v,r+1-v。

int main(){
 cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
    cin>>m;
    for(int i=1;i<=m;i++){
int l,r,v;
        cin>>l>>r>>v;
        sum[l]+=v;
        sum[r+1]-=v;
    }
    for(int i=1;i<=n;i++){
sum[i]+=sum[i-1];
    }
    for(int i=1;i<=n;i++){
     cout<<a[i]+sum[i];   
        putchar('\n');
    }
}

六.I/O

freopen("xxx.in","r",stdin);//文件in开启

freopen("xxx.out","w",stdout)//文件out开启;

fclose(stdin);//文件in关闭

fclose(stdout);//文件out关闭

快读快写:

#include<bits/stdc++.h>
using namespace std;
inline int intfr()
{
	int x = 0;
	bool sign = 0;
	char ch = getchar();
	while(!(ch >= 48 && ch <= 57) && ch != EOF)
	{
		if(ch == '-')
		{
			sign = 1;
		}
		ch = getchar();
	}
	while(ch >= 48 && ch <= 57)
	{
		x = (x << 1) + (x << 3) + (ch - 48);
		ch = getchar();
	}
	if(sign == 1)
	{
		return -x;
	}
	else
	{
		return x;
	}
}
inline void intfp(int x)
{
	char st[105];
	int top = 0;
	if(x < 0)
	{
		putchar('-');
	}
	do
	{
		top++;
		if(x >= 0)
		{
			st[top] = (x % 10 + 48);
		}
		else
		{
			st[top] = (-(x % 10) + 48);
		}
		x /= 10;
	}
	while(x != 0);
	while(top != 0)
	{
		putchar(st[top]);
		top--;
	}
}
inline long long llfr()
{
	long long x = 0;
	bool sign = 0;
	char ch = getchar();
	while(!(ch >= 48 && ch <= 57) && ch != EOF)
	{
		if(ch == '-')
		{
			sign = 1;
		}
		ch = getchar();
	}
	while(ch >= 48 && ch <= 57)
	{
		x = (x << 1) + (x << 3) + (ch - 48);
		ch = getchar();
	}
	if(sign == 1)
	{
		return -x;
	}
	else
	{
		return x;
	}
}
inline void llfp(long long x)
{
	char st[105];
	int top = 0;
	if(x < 0)
	{
		putchar('-');
	}
	do
	{
		top++;
		if(x >= 0)
		{
			st[top] = (x % 10 + 48);
		}
		else
		{
			st[top] = (-(x % 10) + 48);
		}
		x /= 10;
	}
	while(x != 0);
	while(top != 0)
	{
		putchar(st[top]);
		top--;
	}
} 
inline void llwriteln(long long x){
    llfp(x);
    putchar('/n');
}
inline void solve(){
    int n=5000000;
    int v;
    for(int i=1;i<=n;i++)v=llfr();
    for(int i=1;i<=n;i++)llwriteln(i);
}
int main(){
    freopen("in.in","r",stdin);
    freopen("in.out","w",stdout);
  solve();
return 0;
}

但cout<<i<<'\n'最快。比llfp快。

endl耗时太大,大约13s左右。(.时间复杂度随数值个数增长)

七.常数优化

ios::sync_with_stdio(0),cin/cout.tie(0)等称为卡常数。

#include<bits/stdc++.h>
using namespace std;
mt19937 Rand(time(0));
int z[5000000],y[5000000];
int main(){
    int n=5000000;
    for(int i=0;i<n;i++){
   y[i]=i;
    }
    random_shuffle(y,y+n);
    for(int i=0;i<n;i++){
     z[y[i]]=Rand();   //0.4412s
       // z[i]=Rand();//0.4212s
    }
return 0;
}

八.运算符

九.二进制移位

x/2=x>>1

x^2=x<<1

Day 2

The first lesson

一。倍增(st)

求从a[i]开始的2^i个数的最大值

#include<bits/stdc++.h>
using namespace std;
int n,a[114514],f[100010][20];
int main(){
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)f[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;i+(i<<(j-1))<=n;i++)
    f[i][j]=max(f[i][j-1],f[i+(i<<(j-1))][j-1]);
 return 0;   
}

 

求区间中的最大值
 #include<bits/stdc++.h>
using namespace std;
int n,a[114514],f[100010][20],x[114514];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    x[1]=0;
    for(int i=2;i<=n;i++)x[i]=x[i>>1]+1;
    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;i+(i<<(j-1))<=n;i++)
    f[i][j]=max(f[i][j-1],f[i+(i<<(j-1))][j-1]);
    x[1]=0;
     for(int i=2;i<=n;i++)x[i]=x[i>>1]+1;
    cin>>m;
    for(int i=1;i<=m;i++){
int l,r;
        cin>>l>>r;
        int len=r-l+1;
        int j=x[len];
        cout<<max(f[l][j],f[r-(1<<j)+1,[j])<<'\n';
    }
 return 0;   
}

二.(1)二分法

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[114514];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+n+1);
    cin>>m;
    for(int i=1;i<=m;i++){
     int x;
        cin>>x;
        int l=0,r=n;
        while(l+1!=r){
         int z=(l+r)>>1;
            if(x<=a[z])r=z;
            else l=z;
        }
        if(a[r]==x)cout<<"Yes";
        else cout<<"No";
    }
return 0;
}

(2)二分答案

检查函数:

inline void check(int t){
int sum=0;
    for(int i=1;i<=n;++)
        if(a[i]>t)sum+=(a[i]-t-1)/k+1;
    if(sum<=t)return 1;
    else return 0;
}

代码:

 

#include<bits/stdc++.h>
using namespace std;
int k;
inline void check(int t){
int sum=0;
    for(int i=1;i<=n;i++)
        if(a[i]>t)sum+=(a[i]-t-1)/k+1;
    if(sum<=t)return 1;
    else return 0;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+n+1);
    int l=0,r=a[n];
    while(l+1!=r){
cin>>k;
        
    }
return 0;
}

三.快速幂

int ksm(int x,int y,int p){
    if(y==0)return 1;
  int z=ksm(x,y/2,p);
    z=1ll*z*z%p;
    if(y&1)z=1ll*z*x%p;
    return z;
}

四.(一)矩阵

(二)构造函数

(三)矩阵乘法

struct matrix{ 
    int n,m;
  int a[5][5];
    matrix(){
     n=m=0;
        memset(a,0,sizeof(a));
    }
};
matrix operator*(const matrix &ml,const matrix &m2){
 matrix m3;
    m3.n=m1.n;m3.m=m1.m;
    for(int i=1;i<=m3.n;i++){
     for(int j=1;j<=m3.m;j++){
      for(int k=1;k<=m1.m;k++){
       m3.a[i][j]+=m1.a[i][k]*m2.a[k][j];   
      }
     }
    }
    return m3;
}

(四)由于作者是一个蒟蒻,所以矩阵快速幂没记完。(晚上补充)

The second lesson

一.贪心

P1080
 #include<bits/stdc++.h>
using namespace std;
int n;
struct Person{
	int l,r;
}p[1005];
// p[0]设为国王,p[1]~p[n]为大臣
bool cmp(Person a,Person b){
	return max(b.r,a.l*a.r)<max(a.r,b.l*b.r);
	//a排在b前得到最多奖赏比较少 
} 
int s[4005],d[4005],ans[4005]; 
int LEN=4004;

void cheng(int x){//高精度*单精度 
	for(int i=1;i<=LEN;i++) s[i]=s[i]*x;
	//进位
	for(int i=1;i<=LEN;i++){
		s[i+1]+=s[i]/10;
		s[i]%=10;
	} 
}
void chu(int x){//高精度/单精度 
	//从s最高位开始除 
	memset(d,0,sizeof(d));
	int r=0;//余数 
	for(int i=LEN;i>=1;i--){
		r=r*10+s[i];//当前的被除数
		d[i]=r/x;
		r=r%x; 
	} 
} 
bool f(){
	//比较的是ans和d数组 
	for(int i=LEN;i>=1;i--){
		if(ans[i]>d[i]) return false;
		if(ans[i]<d[i]) return true;
	}
	return false;
} 
void cpy(){
	//把d赋值给ans 
	for(int i=1;i<=LEN;i++) ans[i]=d[i];
} 
void print(){
	//输出ans数组 
	while(ans[LEN]==0&&LEN>1) LEN--;//去前导0
	for(int i=LEN;i>=1;i--) cout<<ans[i]; 
}
 
int main(){
    cin>>n;
    for(int i=0;i<=n;i++) cin>>p[i].l>>p[i].r;
    sort(p+1,p+n+1,cmp);
    s[1]=1; 
    for(int i=1;i<=n;i++){
    	cheng(p[i-1].l); //前i-1个大臣左手的乘积
    	//高精度乘 s[] 
		chu(p[i].r);//第i个大臣的奖赏 
		//高精度除 d[] 
		
		if(f()) cpy();
		//高精度比较 
		//高精度赋值 
	}
	print();
	return 0;
}

二.dfs(深度优先搜索)

void dfs(int now,int nownum,int nowsum){
 //当前要看第now个元素选不选
    //已经选了nowsum个数
    //已经选了的数的和是nowsum
    if(now>n){
   dfs(now+1,nownum,nowsum);
        dfs(now+1,nownum+1,nowsum+a[now]);
    }
}

dfs示意

劣势:时间长,一条路走到黑

三.bfs(广度优先搜索)

int step[maxn][maxn],a[maxn][maxn],n,m,sx,sy,tx,ty;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
queue<pair<int,int> >q;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    cin>>sx>>sy;
    cin>>tx>>ty;
    memset(step,-1,sizeof(step));
    step[sx][sy]=0;
    q.push(make_pair(sx,sy));
    while(q.size()){
int x=q.front().first;
        int y=q.front().second;
        q.pop();
        for(int i=0;i<4;i++)
    }
return 0;
}

四.搜索剪枝

#include<bits/stdc++.h>
using namespace std;
int ans=0,n,m,a[114514],sum[114514];
void dfs(int now,int nownum,int nowsum){
 //当前要看第now个元素选不选
    //已经选了nowsum个数
    //已经选了的数的和是nowsum
    if(nownum>m)return;//可行性剪枝
    if(nownum+n-now+1<m)return;
    if(nowsum+sum[n]-sum[now-1]<=ans)return;//最优性剪枝
    if(now>n){
if(nownum==m)ans=max(ans,nowsum);
        return;
    }   
    dfs(now+1,nownum,nowsum);
        dfs(now+1,nownum+1,nowsum+a[now]);
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        for(int i=1;i<=n;i++)
        sum[i]+=sum[i-1]+a[i];
        dfs(1,0,0);
        cout<<ans<<'\n''
 return 0;   
}

 

五.搜索卡时

在0.95s时break

#include<bits/stdc++.h>
using namespace std;
int ans=0,n,m,a[114514],sum[114514];
void dfs(int now,int nownum,int nowsum){
 //当前要看第now个元素选不选
    //已经选了nowsum个数
    //已经选了的数的和是nowsu
    //clock()//程序运行了多少秒
    if(1000*clock()/CLOCKS_PER_SEC>900)exit(0);//卡时
    if(nownum>m)return;//可行性剪枝
    if(nownum+n-now+1<m)return;
    if(nowsum+sum[n]-sum[now-1]<=ans)return;//最优性剪枝
    if(now>n){
if(nownum==m)ans=max(ans,nowsum);
        return;
    }   
    dfs(now+1,nownum,nowsum);
        dfs(now+1,nownum+1,nowsum+a[now]);
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        for(int i=1;i<=n;i++)
        sum[i]+=sum[i-1]+a[i];
        dfs(1,0,0);
        cout<<ans<<'\n''
 return 0;   
}

六。搜索玄学(zhx说的,不关我事)

倒着搜。

Day 3

The first lesson

一.dfs重现

#include<bits/stdc++.h>
using namespace std;
int pos[20],ans=0;
int n;
bool col[20];
bool xie1[50];
bool xie2[50];
inline void dfs(int now){
 if(now>n)ans++; return;
    int up=n;
    if(now==1)up=up>>1;
    for(int j=1;j<=n;j++){
        int idx1=j-now+n;
        int idx2=now+j-1;
        if(!col[j]&&!xie1[idx1]=xie2[idx2]){
pos[now]=j;
            col[j]=xie1[idx1]=xie2[idx2]=true;
            dfs(now+1);
            col[j]=xie1[idx1]=xie2[idx2]=false;
        }
    }
}
signed main(){
 cin>>n;
    dfs(1);
    cout<<(ans<<1)<<'\n';
}

优化
 #include<bits/stdc++.h>
using namespace std;
int pos[20],ans=0;
int n;
inline void dfs(int now){
 if(now>n)ans++; return;
    int up=n;
    if(now==1)up=up>>1;
    int s=s1|s2|s3;
    for(int j=0;j<n;j++){
        if(((s>>j)&1)==0){
            pos[now]=j;
            dfs(now+1,s1|(1<<j),s2|(1<<j),s3|(1<<j));
       
        }
    }
}
signed main(){
 cin>>n;
    dfs(0,0,0,0);
    cout<<(ans<<1)<<'\n';
}

2.BFS重现

#include<bits/stdc++.h>
using namespace std;
queue<int>q;
int a[4][4],b[4][4],step[3265920],dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int main(){
    int s=0;
    for(int i=1;i<=3;i++){
        for(int j=1;j<=3;j++){
         cin>>a[i][j];
            s=s*10+a[i][j];
           }
    }
        memset(step,-1,sizeof(step));
 step[s]=0;
    q.push(s);
    while(q.size()){
     int ss=q.front();
         int cur_step=step[s];
         q.pop(); 
        int x,y;
        memset(vis,0,sizeof(vis));
        for(int i=3;i>=1;i--){
            for(int j=3;j>=1;j--){
a[i][j]=s%10;
            s=s/10;
            if(a[i][j]==0)x=i,y=j;
            }
        }
        for(int d=0;d<4;d++){
int xx=x+dx[i];
            int yy=y+dy[d];
        if(xx>=1&&xx<=3&&yy>=1&&yy<=3){
         swap(a[x][y],a[xx][yy]);
            s=0;
            for(int i=1;i<=3;i++){
             for(int j=1;j<=3;j++){
              s=s*10+a[i][j];
             }
            }
        }
        }
    }
return 0;
}

阶乘优化(换成9进制)

三.如何优化BFS

1.双向BFS

The second lesson

一.图论

vector<pair<int,int> >z[maxn];
inline add_edge(int s,int e,int d){
    z[s].push_back(make_pair(e,d));
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
     int s,e,d;
        cin>>s>>e>>d;
        add_edge(s,e,d);
        add_edge(e,s,d);
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<z[i].size();j++){
         int e=z[i][j].first;
            int d=z[i[j].second;
        }
    }
}

填色

vector<pair<int,int> >z[maxn];
inline add_edge(int s,int e,int d){
    z[s].push_back(make_pair(e,d));
}
int col[maxn];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
     int s,e,d;
        cin>>s>>e>>d;
        add_edge(s,e,d);
        add_edge(e,s,d);
    }
    for(int i=1;i<=n;i++){
     if(col[i]!=0)continue;   
    col[1]=1;
    queue<int>q;
    q.push(1);
    while(q.size()){
int i=q.front();
        q.pop();
        for(int j=0;j<z[i].size();j++){
         int k=z[i][j];
            if(!col[k]){
             col[k]=3-col[i];
                q.push(k);
            }
            else{
             if(col[k]==col[i]){
                 cout<<"bushierfentu";
                 exit(0);
                 }
        }
    }
        cout<<"shierfentu";
}

倍增求lca
#include<bits/stdc++.h>
using namespace std;
vector<int>z[maxn];
int n,m;
inline void add_edge(int s,int e){
z[s].push_back(e);
}
int depth[maxn],f[maxn][20];
inline void dfs(int i,int j){
   f[i][0]=j;
    for(int k=1;k<=19;k++)f[1][k]=f[f[i][k-1]][k-1];
    depth[i]=depth[j]+1;
    for(int k=0;k<z[i].size();k++){
   int l=z[i][k];
        if(l!=j)dfs(l,i);
    }
}
inline int get_lca(int p1,int p2){
  if(depth[p1]<depth[p2])swap(p1,p2);
    for(int i=19;i>=0;i--)if(depth[f[p1][i]]>=depth[p2])p1=f[p1][i];
    if(p1==p2)return p1;
    for(int i=19;i>=0;i--)if(f[p1)[i]!=f[p2][i]}p1=f[p1][i],p2=f[p2][i];
   return f[p1][0];   
       }
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int s,e;
        cin>>s>>e;
        add_edge(s,e);
        add_edge(e,s);
    }
    dfs(1,0);
    cout<<get_lca();
 return 0;   
}

Day 4

The First lesson

一.最短路

(1)floyd算法//O(n^3)

本质是dp.

#define maxn 100
int dist[maxn][maxn][maxn];
int main(){
    memset(dist,0x3f,sizeof(dist));
    cin>>n>>m;
    for(int i=1;i<=n;i++{
     int s,e,d;
        cin>>s>>e>>d;
        dist[0][s][e]=min(dist[0][s][e],d);
    }
        for(int i=1;i<=n;i++){
         dist[0][i][i]=0;   
        }
        for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
 dist[i][j][k]=min(dist[i-1][j][k],dist[i-1][j][i]+dist[i-1][i][k])
}
}
        }
        for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
 cout<<dist[n][i][j]<<'\n';
}
        }
return 0;
}

优化:(压维)

#include<bits/stdc++.h>
using namespace std;
#define maxn 100
int dist[maxn][maxn];
int main(){
    memset(dist,0x3f,sizeof(dist));
    cin>>n>>m;
    for(int i=1;i<=n;i++{
     int s,e,d;
        cin>>s>>e>>d;
        dist[s][e]=min(dist[s][e],d);
    }
        for(int i=1;i<=n;i++){
         dist[i][i]=0;   
        }
        for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int k=1;k<=n;k++){
 dist[j][k]=min(dist[j][k],dist[j][i]+dist[i][k])
}
}
        }
        for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
 cout<<dist[i][j]<<'\n';
}
        }
return 0;
}

(2)单源最短路

dijkstra:

vector<pair<int,int> >z[maxn];
inline void add_edge(int a,int b,int c){
z[a].push_back(make_pair(b,c));
    }
inline void dijkstra(int s){
 memset(dist,0x3f,sizeof(dist));
    dist[s]=0;
    for(int i=1;i<=n;i++){
     int p=0;
        for(int j=1;j<=n;j++){
         if(!vis[j]&&(p==0||dist[j]<dist[p]))p=j;
        }
        vis[p]=true;
        for(int j=1;j<=z[p].size();j++){
            int q.z[p][j].first;
            int d=z[p][j].second;
            if(dist[q]>dist[p]+d)dist[q]=dist[p]+d;
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
int s,e,d;
        cin>>s>>e>>d;
        add_edge(s,e,d);
    }
    dijkstra();
    for(int i=1;i<=n;i++){
     cout<<dist[i]<<'\n';   
    }
 return 0;   
}

spfa: 

vector<pair<int,int> >z[maxn];
inline void add_edge(int a,int b,q.frint c){
z[a].push_back(make_pair(b,c));
    }
inline void spfa(int s){
 memset(dist,0x3f,sizeof(dist));
    dist[s]=0;
    queue<int>q;
    q.push(s);
    vis[s]=true;
    while(q.size()){
int p=q.front();
        q.pop();
        vis[p]=false;
        for(int i=0;i<z[p].size();i++){
         int e=z[p][i].first;
            int d=z[p][i].second;
            if(dist[e]>dist[p]+d){
             dist[e]=dist[p]+d;
                if(!vis[e])q.push(e),vis[e]=true;
            }
        }
    }
    for(int i=1;i<=n;i++){
     int p=0;
        for(int j=1;j<=n;j++){
         if(!vis[j]&&(p==0||dist[j]<dist[p]))p=j;
        }
        vis[p]=true;
        for(int j=1;j<=z[p].size();j++){
            int q.z[p][j].first;
            int d=z[p][j].second;
            if(dist[q]>dist[p]+d)dist[q]=dist[p]+d;
        }
    }
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
int s,e,d;
        cin>>s>>e>>d;
        add_edge(s,e,d);
    }
    spfa();
    for(int i=1;i<=n;i++){
     cout<<dist[i]<<'\n';   
    }
 return 0;   
}

The second lesson

一.生成树

kruscal算法:

#include<bits/stdc++.h>
using namespace std;
#define maxn 1414114
int to[maxn];
inline int go(int p){
if(to[p]==p)return p;
    else return to[p]=go(to[p]);
}
inline bool cmp(edge a,edge b){
return a.d<b.d;
}
struct edge{
  int s,e,d;
}ed[maxn];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>ed[i].s>>ed[i].e>>ed[i].d;
    sort(ed+1,ed+m+1,cmp);
    for(int i=1;i<=n;i++)to[i]=i;
    int ans=0;
    for(int i=1;i<=m;i++){
     int p1=ed[i].s,p2=ed[i].e,d=ed[i].d;
        if(go(p1)!=go(p2)){
         ans+=d;
            to[go(p1)]=go(p2);
        }
    }
    cout<<ans<<'\n';
return 0;
}

Day 5

The First Lesson

一.二分图匹配

(一)匈牙利算法

 二.强连通问题

The second Lesson

动态规划(DP)

需运用递推式。

int f[maxn];
bool g[maxn];
int dfs(int n){//记忆化搜索(a*)
 if(n==0)return 0;
    if(n==1)return 1;
    if(g[n])return f[n];
    g[n]=true;
    f[n]=dfs(n-1)+dfs(n-2);
    return dfs(n-1)+dfs(n-2);
}
int main(){
 cin>>n;
    f[0]=0;
    f[1]=1;
   /*for(int i=2;i<=n;i++){
     f[i]=f[i-1]+f[i-2];
    }*/
    /*for(int i=0;i<=n;i++){
     f[i+1]+=f[i];
        f[i+2]+=f[i];
    }*/
    //cout<<f[n]<<'\n';
    cout<<dfs(n)<<'\n';
}

 

int main(){
 cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    f[1][1]=a[1][1];
    for(int i-1;i<=n;i++)
        for(int j=1;j<=m;j++)
            f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
         f[i+1][j]=max(f[i+1][j],f[i][j]+a[i+1][j]);   
        }
}

最长上升子序列(LIS)

#include<bits/stdc++.h>
using namespace std;
#define maxn 114514
int f[maxn];
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
     cin>>a[i];   
    }
    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]);
    f[i]++;
}
        int ans=0;
        for(int i=1;i<=n;i++)
            ans=max(ans,f[i]);
        cout<<ans<<'\n'; 
    return 0;   
    }

分类:

#include<bits/stdc++.h>
using namespace std;
int f[1005][1005];
int n;
signed main(){
cin>>n;
    f[1][0]=1;
    for(int i=1;i<=n;i++){
     for(int j=0;j<=i*(i-1)/2;i++){
         for(int k=0;k<=i;k++){
   f[i+1][j+i-k]+=f[i][j];
         }
     }
    }
    int ans=0;
    for(int j=0;j<=n*(n-1)/2;j+=2)ans+=f[n][j];
    cout<<ans<<'\n';
}

'

Day 6

动态规划(DP)

背包DP

#include<bits/stdc++.h>
using namespace std;
int f[1145][1145],v[1145],w[1145];
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
     cin>v[i]>>w[i];   
    }
    for(int i=0;i<n;i++){
for(int j=0;j<=m;j++){
 f[i+1][j]=max(f[i][j],f[i+1][j]);
    f[i+1][j+v[i+1]]=max(f[i+1][j+v[i+1]],f[i][j]+w[i+1]);
}
    }
    int ans=0;
    for(int i=0;i<=m;i++){
     ans=max(ans,f[n][i]);   
    }
    cout<<ans<<'\n';
 return 0;
}

 区间DP

int f[maxn][maxn];
int main(){
 cin>>n;
    for(int i=1;i<=n;i++){
     cin>>a[i];   
    }
    for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i];
    }
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=n;i++){
f[i][i]=0;
    }
    for(int l=1;l<=n;l++)
        for(int r=l;r<=n;r++)
            for(int k=l;k<r;k++)
                f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+sum[r]-sum[l-1]);
    cout<<f[1][n]<<'\n';
}

  

树形DP

int f[maxn];
vector<int>z[maxn];
inline void add_edge(int s,int e){
z[s][e].push_back(s,e);
}
void dfs(int p,int f){
    for(int i=0;i<z[p].size();i++){
int q=z[p][i];
        if(q!=f)dfs(q,p);
    }
    f[p]=1;
    for(int i=0;i<z[p].size;i++){
     int q=z[p][i];
        if(q!=f)f[p]+=f[q];
    }
}
int main()[
    cin>>n;
    for(int i=1;i<n;i++){
int s,e;
        cin>>s>>e;
        add_edge(s,e);
        add_edge(e,s);
    }
    dfs(1,0);
    }

数位DP

int f[30][2];
int get(int x){
int n=0;
    while(x_!=0){
n++;               
        x[n]=x_%10;
        x_/=10;    
    }        
    memset(f,0,sizeof(f));
    f[n+1][1]=1;
    for(int i=n;i>=1;i--)
     for(int j=0;j<2;j++){
      int up=9;
         if(j==1)up=x[i];
         for(int k=0;k<=up;k++)
             f[i][(j==1)&&(k==up)]+=f[i+1][j];
    }
    return f[1][0]+f[1][1];
}
int main(){
 cin>l>>r;
    cout<<get(r)-get(l-1)<<endl;
}

      

posted @ 2023-07-09 10:11  Lsr_Konnyaku  阅读(67)  评论(0)    收藏  举报