蓝桥18天冲击记录

3.22

第一题 区间和(离散化+去重操作+二分查找)

int unique()
{
    int j=0;
    for(int i=0;i<k;i++)
    {
        if(!i||alls[i]!=alls[i-1])
       alls[j++]=alls[i];
    }
    return j;
}
//去重 返回下标

第二题 差分(理解实现差分功能的函数的意义)

void insert(int l,int r,int c)//实现当对b[n]求和的时候,求和的结果a[n]在区间段[l,r]
//上加c
{
    b[l]+=c;
    b[r+1]-=c;
}

3.23

第一题 bfs走迷宫

int bfs(int sx,int sy,int ex,int ey)
{
	queue<pair<int,int>>q;
	q.push({ sx,sy });
	memset(d, -1, sizeof d);
	d[sx][sy] = 0;
	while(!q.empty())
	{
		auto p = q.front(); q.pop();
		for (int i = 0; i < 4; i++)
		{
			int x = p.first + dx[i];
			int y = p.second + dy[i];
			if (x >= 1 && x <= n && y >= 1 && y <= m && d[x][y] == -1&&g[x][y]=='1')
			{
				q.push({ x,y });
				d[x][y] = d[p.first][p.second] + 1;
				if (x == ex && y == ey)return d[x][y];
			}
		}
	}
	return d[ex][ey];
}

第二题 并查集

#include<iostream>
using namespace std;
const int N=1e5+10;
int f[N];
int find(int x)//寻找x的祖先并且路径压缩
{
    if(x!=f[x])f[x]=find(f[x]);
    return f[x];
}
int main()
{
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++)
    f[i]=i;
    while(m--)
    {
        char op;cin>>op;
        int a,b;
        if(op=='M')
        {
            cin>>a>>b;
            f[find(a)]=find(b);
        }
        else
        {
            cin>>a>>b;
            if(find(a)==find(b))
            cout<<"Yes"<<endl;
            else
            cout<<"No"<<endl;
        }
    }
    return 0;
}

3.27(2h)

首先复习了bfs走迷宫,并查集网络分析

然后复习dp,01背包问题,数字三角形,最长上升子序列

然后做了一道数学模拟题 两个闹钟

4379. 两个闹钟 - AcWing题库

3.28

单调栈

表达式求值

八数码(注意到unordered_map比map要快)

int bfs(string start)
{
    queue<string>q;
    unordered_map<string,int>d;
    q.push(start);
    d[start]=0;
    string end="12345678x";
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        int distance=d[t];
        if(t==end)return distance;
        int k=t.find('x');
        int x=k/3,y=k%3;
        for(int i=0;i<4;i++)
        {
            int a=x+dx[i],b=y+dy[i];
            if(a>=0&&a<3&&b>=0&&b<3)
            {
                swap(t[3*a+b],t[k]);
                if(!d.count(t))
                {
                    d[t]=distance+1;
                    q.push(t);
                }
                swap(t[a*3+b],t[k]);
            }
        }
    }
    return -1;
}

皇后问题(注意到对于对角线和反对角线的映射)

void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i<n;i++)
        cout<<g[i]<<endl;
        cout<<endl;
        return;
    }
    else
    {
        for(int i=0;i<n;i++)
        {
            if(!col[i]&&!dg[u+i]&&!udg[n+u-i])
            {
                g[u][i]='Q';
                col[i]=dg[u+i]=udg[n-u+i]=1;
                dfs(u+1);
                col[i]=dg[u+i]=udg[n-u+i]=0;//恢复现场
                g[u][i]='.';
            }
        }
    }
}

最长公共子序列

学会对复杂问题进行状态转移的思考

for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        if(a[i]==b[j])f[i][j]=f[i-1][j-1]+1;
        else
        {
            f[i][j]=max(f[i-1][j],f[i][j-1]);
        }
    }

筛质数

int main()
{
    cin>>n;
    int cnt=0;
    for(int i=2;i<=n;i++)
    {
        if(!st[i])primes[cnt++]=i;
            for(int j=0;primes[j]*i<=n&&primes[j];j++)
            {
                st[primes[j]*i]=1;
                if(i%primes[j]==0)break;
//如果此时不停止,那么后面被筛的数字的最小质因数就是primes[j]了,这意味着它会被重复晒
            }
        
    }
    cout<<cnt<<endl;
}

质因数分解定理

oid divide(int n)
{
    for(int i=2;i*i<=n;i++)
    //只需要枚举到小于sqrt(n)的质因子
    //因为大于sqrt(n)的质因子必然只有一个
    if(n%i==0)
    {
        int s=0;
        while(n%i==0)
        {
            n/=i;
            s++;
        }
        cout<<i<<' '<<s<<endl;
    }
    if(n>1)cout<<n<<' '<<1<<endl;
    //如果大于sqrt(n)的质因子有一个的话,输出它
}

欧几里得算法

int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}

约数数量

#include<iostream>
#include<unordered_map>
 
const int mod=1e9+7;
 
using namespace std;
unordered_map<int,int>primes;
int main()
{
    int n;cin>>n;
    while(n--)
    {
    int x;cin>>x;
    for(int i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            while(x%i==0)
            {
             primes[i]++;
             x/=i;
            }
        }
    }
    if(x>1)primes[x]++;
    }
    long long ans=1;
   for(auto it=primes.begin();it!=primes.end();it++)
   {
       ans=ans*(1+it->second)%mod;
   }
    cout<<ans%mod<<endl;
    
}

约数之和

对于等比数列求和

假设指数为t,底数为x

则sum的求法为

while(t--)
{
  tmp=tmp*x+1;
}
  for(auto it=primes.begin();it !=primes.end();it++)
     {
         long long tmp=1;
         int t=it->second;
         while(t--)
         {
             tmp=(tmp*it->first+1)%mod;
         }
         sum=sum*tmp%mod;
         //虽然能保证tmp不大于mod,但如果sum*tmp很有可能大于mod
     }

欧拉函数

记住公式

#include<iostream>
using namespace std;
int n;
int main()
{
    cin>>n;
    while(n--)
    {
        int x;
        cin>>x;
        int res=x;
        for(int i=2;i<=x/i;i++)
        {
            if(x%i==0)
            {
                res=res/i*(i-1);
                while(x%i==0)x/=i;
            }
        }
        if(x>1)res=res/x*(x-1);
        cout<<res<<endl;
    }
    
}

 线性筛求欧拉函数

 

ll get_phi()
{
    int cnt=0;
    phi[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!st[i])
        {
            primes[cnt++]=i;
            phi[i]=i-1;
        }
        for(int j=0;primes[j]*i<=n&&primes[j];j++)
        {
            st[primes[j]*i]=1;
            if(i%primes[j]==0)
            {
                phi[primes[j]*i]=phi[i]*primes[j];
                break;
            }
            phi[primes[j]*i]=phi[i]*(primes[j]-1);
        }
    }
    ll sum=0;
    for(int i=1;i<=n;i++)
    sum+=phi[i];
    return sum;
}

容斥原理

求所有质数选法的并集

n个圈相并=1个圈-2个圈+3个圈-4个圈+5个圈……

奇数圈加,偶数圈减

 for(int i=1;i<1<<m;i++)
    //这里表示一共有1-2^m-1种选法,对应其二进制数
    {
        ll cnt=0,t=1;
        for(int j=0;j<m;j++)
        {//对于每一个质数的选取方案通过j来访问遍历
            if(i>>j&1)
            {
                 cnt++;
                 if(t*p[j]>n)
                 {
                     t=-1;
                     break;
                 }
                 //如果当前方案的最小公倍数已经超过范围了,则跳过此方案
                 t*=p[j];
            }
        }
        if(t!=-1)
        {
            if(cnt&1)
            res+=n/t;
            //寻找在1-n中有多少t的公倍数
            else
            res-=n/t;
        }
    }

二维前缀和

s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
//求二维前缀和的公式
s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
//求区间(x1,y1)到(x2,y2)的区间和公式

 二维差分

void insert(int x1,int y1,int x2,int y2,int c)
{
    b[x1][y1]+=c;
    b[x2+1][y1]-=c;
    b[x1][y2+1]-=c;
    b[x2+1][y2+1]+=c;
}

区间维护

int merge()
{
    vector<pii>res;
    int st=-1e9,ed=-1e9;
    for(auto &seg:segs)
    {
        if(st==-1e9)
        {
            st=seg.first,ed=seg.second;
        }//放入第一个区间
        else
        {
            if(seg.first>ed)//维护新区间
            {
                res.push_back({st,ed});
        
                st=seg.first,ed=seg.second;
            }
            else
            ed=max(ed,seg.second);
        }
    }
    res.push_back({st,ed});
    return res.size();
}

双指针

int main()
{
    int n;cin>>n;int j=1,res=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        s[a[i]]++;
               while(s[a[i]]!=1)
            {
                s[a[j]]--;
                j++;
            }
         res=max(i-j+1,res);
    }
    cout<<res<<endl;
}

数组目标和

int main()
{
  int n,m,x;cin>>n>>m>>x;
  for(int i=0;i<n;i++)
  cin>>a[i];
  for(int j=0;j<m;j++)
  cin>>b[j];
  for(int i=0,j=m-1;i<n;i++)
  {
      while(a[i]+b[j]>x&&j>=0)
      {
          j--;
      }
      if(a[i]+b[j]==x)
      cout<<i<<' '<<j<<endl;
  }
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nathan Qian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值