蓝桥最后一周

本文介绍了多个编程挑战,包括等腰三角形的模拟、数字的排列、并查集操作、数的范围查找、四平方和问题、立方根的二分查找以及走迷宫的BFS算法。这些挑战涵盖了不同的算法和数据结构,如动态规划、深度优先搜索、二分查找和并查集,旨在提升编程和问题解决能力。
摘要由CSDN通过智能技术生成

模拟 等腰三角形

活动 - AcWing

#include<iostream>
using namespace std;
const int N = 1010;
char a[N][N];
char s[2 * N];
int main()
{
	int n; cin >> n;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n + i - 1; j++)
			a[i][j] = '.';
	int m = 0;
	for (int i = 1; i < 600; i++)
	{
		int t = i;
		if (t < 10)
		{
			s[++m] = t + '0';
		}
		else
		{
			char tn[4];
			int k = 0;
			while (t)
			{
				tn[k++] = t % 10;
				t /= 10;
			}
			for (int x = k - 1; x >= 0; x--)
			{
				s[++m] = tn[x] + '0';
			}
		}
	}
	int t = 0;
	for (int i = 1; i <= n; i++)
	{
		a[i][n - (i-1)] = s[++t];
	}
	for (int i = 2; i <= n + n - 1; i++)
	{
		a[n][i] = s[++t];
	}
	for (int i = n - 1; i > 1; i--)
	{
		a[i][n + i - 1] = s[++t];
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n + i - 1; j++)
		{
			cout << a[i][j];
		}
		cout << endl;
	}
	return 0;
}

排列数字

#include<iostream>
using namespace std;
const int N=10;
int n;
bool st[N];
int path[N];
void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i<n;i++)
        cout<<path[i]<<' ';
        cout<<endl;
        return;
    }
    for(int i=1;i<=n;i++)
    {
        if(!st[i])
        {
            path[u]=i;
            st[i]=1;
            dfs(u+1);
            st[i]=0;
        }
    }
}
int main()
{
    cin>>n;
    dfs(0);
}

并查集

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int f[N];
int m, n;
int find(int x)
{
    if (x != f[x])f[x] = find(f[x]);
    return f[x];
}
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        f[i] = i;
    while (m--)
    {
        char op; int a, b;
        cin >> op >> a >> b;
        if (op == 'M')
        {
            f[find(a)] = find(b);
        }
        else
        {
            if (find(a) == find(b))
                cout << "Yes" << endl;
            else
                cout << "No" << endl;
        }

    }

}

 第十三届真题

刷题统计

#include<iostream>
using namespace std;
#define ll long long
ll a,b,n;
int main()
{
    cin>>a>>b>>n;
    ll week=5*a+2*b;
    ll day=n/week*7;
    n%=week;
    ll d[]={a,a,a,a,a,b,b};
    for(int i=0;n>0;i++)
    {
        n-=d[i];
        day++;
    }
    cout<<day<<endl;
}

修剪树木

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

X进制减法

#pragma GCC optimize(2)
#include<iostream>
using namespace std;
#define ll long long
const int mod=1000000007;
const int N=1e5+10;
ll a[N],b[N];
int main()
{
    ll ma,mb,n;
    cin>>n>>ma;
    for(int i=ma-1;i>=0;i--)
    cin>>a[i];
    cin>>mb;
    for(int i=mb-1;i>=0;i--)
    cin>>b[i];
    int t,w;
    ll mul=1,res=0;
    for(int i=0;i<mb||i<ma;i++)
    {
        res=(res+(a[i]-b[i]+mod)%mod*mul%mod)%mod;
        t=max(a[i],b[i]);
        w=max(t+1,2);
        mul=mul*w%mod;
    }
    cout<<res<<endl;
}

统计子矩阵

#pragma GCC optimize(2)
#include<iostream>
using namespace std;
#define ll long long
const int N=510;
ll n,m,k;
ll s[N][N];
ll calc(int x1,int y1,int x2,int y2)
{
    return s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
}
int main()
{
    cin>>n>>m>>k;
    int x;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        cin>>x;
        s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+x;
    }
    ll cnt=0;
    for(int l=1;l<=m;l++)
    for(int r=l;r<=m;r++)
    for(int i=1,j=1;i<=n;i++)
    {
        while(j<=i&&calc(j,l,i,r)>k)j++;
        if(j<=i)cnt+=i-j+1;
    }
    cout<<cnt<<endl;
    
}

积木画 状态DP

#pragma GCC optimize(2)
#include<iostream>
using namespace std;
#define ll long long
const int mod=1000000007;
const int N=1e7+10;
int n;
ll g[4][4]=
{
{1,1,1,1},
{0,0,1,1},
{0,1,0,1},
{1,0,0,0}
};
int f[N][4];
int main()
{
    cin>>n;
    f[1][0]=1;
    for(int i=1;i<=n;i++)
    for(int j=0;j<4;j++)
    for(int k=0;k<4;k++)
    {
    f[i+1][k]=(f[i+1][k]+f[i][j]*g[j][k])%mod;
    }
    cout<<f[n+1][0]<<endl;
    
}

数的范围 二分

#include<iostream>
using namespace std;
int n,q;
const int N=1e5+10;
int a[N];
int main()
{
   cin>>n>>q;
   for(int i=0;i<n;i++)
   cin>>a[i];
   while(q--)
   {
       int k;cin>>k;
       int l=0,r=n-1;
       while(l<r)
       {
           int mid=(l+r)/2;
           if(a[mid]>=k)r=mid;
           else
           l=mid+1;
       }//如果有这个数字,返回它的第一个位置
       if(a[l]!=k)
       {
           cout<<"-1 -1"<<endl;
       }
       else//返回该数字的最后一个位置
       {
           cout<<l<<' ';
           l=0,r=n-1;
           while(l<r)
           {
               int mid=(l+r+1)/2;
               if(a[mid]<=k)l=mid;
               else
               r=mid-1;
           }
           cout<<l<<endl;
           
       }
   }
}

四平方和 二分+暴搜

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 5e6 + 10;
struct num
{
    int c;
    int d;
    int sum;
}sum[N];
int n;
bool cmp(num a, num b)
{
    if (a.sum != b.sum)return a.sum < b.sum;
    if (a.c != b.c)return a.c < b.c;
    if (a.d != b.d)return a.d < b.d;
}
int main()
{
    cin >> n;
    int m = 0;
    for (int c = 0; c * c <= n; c++)
        for (int d = c; d * d + c * c <= n; d++)
            sum[m++] = { c,d,d * d + c * c };
    sort(sum, sum + m,cmp);
    for (int a = 0; a * a <= n; a++)
        for (int b = a; b * b + a * a <= n; b++)
        {
            int t = n - (b * b + a * a);
            int l = 0, r = m - 1;
            while (l < r)
            {
                int mid = (l + r) / 2;
                if (sum[mid].sum >= t)r = mid;
                else l = mid + 1;
            }
            if (sum[l].sum == t)
            {
                cout << a << ' ' << b << ' ' << sum[l].c << ' ' << sum[l].d << endl;
                
            }
        }
}

三次方跟 实数二分

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
    double n;
    cin>>n;
    double l=-10000.0,r=10000.0;
    while(r-l>1e-9)//这里尽量比精度稍微大一些
    {
        
        double mid=(l+r)/2;
        if(mid*mid*mid>=n)r=mid;
        else
        l=mid;
    }
    printf("%.6lf",l);
}

走迷宫 BFS

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N=110;
char g[N][N];
int n,m;
struct pii
{
    int x;
    int y;
};
int d[N][N];
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
int bfs()
{
    memset(d,-1,sizeof d);
    queue<pii>q;
    q.push({1,1});
    d[1][1]=0;
    while(!q.empty())
    {
        auto p=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            int x=p.x+dx[i],y=p.y+dy[i];
            if(g[x][y]=='0'&&d[x][y]==-1)
            {
                q.push({x,y});
                d[x][y]=d[p.x][p.y]+1;
                if(x==n&&y==m)
                {
                    return d[x][y];
                }
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    cin>>g[i][j];
    cout<<bfs()<<endl;
    
}

八数码 bfs 该死的读写

#include <iostream>
#include <cstring>
#include <algorithm>
#include<queue>
#include <unordered_map>
using namespace std;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
int bfs(string st)
{
    string ed="12345678x";
    unordered_map<string,int>d;
    queue<string>q;
    d[st]=0;
    q.push(st);
    while(!q.empty())
    {
        auto p=q.front();q.pop();
        int distance=d[p];
        int k=p.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<=2&&a>=0&&b>=0&&b<=2)
            {
                int t=a*3+b;
                swap(p[t],p[k]);
                if(!d.count(p))
                {
                    d[p]=distance+1;
                    q.push(p);
                    if(p==ed)return d[p];
                  
                }
                swap(p[t],p[k]);
            }
        }
        
    }
    return -1;
}
int main()
{
 string st;
 char s[2];
 for(int i=0;i<9;i++)
 {
     cin>>s;
     st+=s[0];
 }
 cout<<bfs(st)<<endl;
}

皇后问题 DFS

对角线映射公式为 u+i

反对角线映射公式为 n+(u-i)

#include<iostream>
using namespace std;
int n;
const int N=20;
char g[N][N];
bool col[N],dg[N],udg[N];
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)]=true;
                dfs(u+1);
                col[i]=dg[u+i]=udg[n+(u-i)]=false;
                g[u][i]='.';
            }
        }
    }
}
int main()
{
    cin>>n;
    for (int i = 0; i < n; i ++ )
    for(int j=0;j<n;j++)
    g[i][j]='.';
    dfs(0);
    
}

DP

背包问题

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main()
{
 cin>>n>>m;
 for(int i=1;i<=n;i++)
 cin>>v[i]>>w[i];
/*状态的转移可以看成
当容积为j的时候,首先不选择第i个物品,那我们可以直接从f[i-1][j]的情况转移过来
如果选择第i个物品,那么前提是当前的空间大小j足够装这个物品,那么我们可以从f[i-1][j-v[i]]转移过来
最终比较下两种方案的大小
*/
 for(int i=1;i<=n;i++)
 for(int j=1;j<=m;j++)
 {
     f[i][j]=f[i-1][j];
     if(j-v[i]>=0)
     f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
 }
 cout<<f[n][m]<<endl;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n,m;
int v[N],w[N];
int f[N];
int main()
{
 cin>>n>>m;
 for(int i=1;i<=n;i++)
 cin>>v[i]>>w[i];
/*状态的转移可以看成
如果不选择 那么此时的f[j]就相当于上一轮的f[j]
如果选择 那么此时的f[j-v[i]]就相当于f[i-1][j-v[i]]
逆序遍历j是为了让上一轮的更新这一轮的f,防止前面的内容被污染
*/
 for(int i=1;i<=n;i++)
 for(int j=m;j>=v[i];j--)
 {
     f[j]=max(f[j],f[j-v[i]]+w[i]);
 }
 cout<<f[m]<<endl;
}

数字三角形 线性dp

注意到权值可能为负数 因此不要用0来初始化数组

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
const int inf=-0x3f3f3f3f;
const int N=510;
int f[N][N];
int w[N][N];
int main()
{
 cin>>n;
 memset(f,inf,sizeof f);
 for(int i=1;i<=n;i++)
 for(int j=1;j<=i;j++)
 cin>>w[i][j];
 f[1][1]=w[1][1];
 for(int i=2;i<=n;i++)
 for(int j=1;j<=i;j++)
 {
     f[i][j]=max(f[i-1][j],f[i-1][j-1])+w[i][j];
 }
 int ma=inf;
 for(int i=1;i<=n;i++)
 ma=max(ma,f[n][i]);
 cout<<ma<<endl;

}

最长上升子序列

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n;
int a[N],f[N];
int main()
{
    cin>>n;int cnt=1;
    cin>>a[1];f[1]=a[1];
    /*
    更新状态数组f[i]下标代表最长子序列的长度
    那么数值代表长度为i的子序列的末尾数字
    如果遇到的数字大于长度为cnt的末尾数字,那么长度+1,更新这个数字
    如果不大于,那么就更新整个状态数组中第一个大于等于该数字的位置
    */
    for (int i = 2; i <= n; i ++ )
    {
        cin>>a[i];
        if(f[cnt]<a[i])
        f[++cnt]=a[i];
        else
        {
            int l=1,r=cnt;
            while(l<r)
            {
                int mid=(l+r)/2;
                if(f[mid]>=a[i])r=mid;
                else
                l=mid+1;
            }
            f[l]=a[i];
        }
    }
    cout<<cnt<<endl;
}

数论

分解质因数

#include<iostream>
using namespace std;
int n;
void divide(int n)
{
    for(int i=2;i*i<=n;i++)
    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;
}
int main()
{
    cin>>n;
    while(n--)
    {
        int m;cin>>m;
        divide(m);
        cout<<endl;
    }
    
}

完全平方数 不开ll拿省四


#include<iostream>
#include <unordered_map>
using namespace std;
#define ll long long

ll divide(ll n)
{
    ll ans=1;
    for(ll i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            int s=0;
            while(n%i==0)
            {
               s++;
                n/=i;
            }
            if(s&1)
            ans*=i;
        }
    }
    if(n>1)ans*=n;
    return ans;
  
}
int main()
{
    ll n;
    cin>>n;
    cout<<divide(n)<<endl;
}

 

筛质数

#include<iostream>
using namespace std;
const int N=1e6+10;
bool st[N];
int prime[N];
int cnt;
int main()
{
    int n;cin>>n;
    for(int i=2;i<=n;i++)
    {
        if(!st[i])prime[cnt++]=i;
        for(int j=0;prime[j]*i<=n&&prime[j];j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0)break;
        }
    }
    cout<<cnt<<endl;
}

约数个数

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

约数之和

对于最高次数为n,最低次数为0的等比数列实现累加公式,公比为x

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

最大公约数

#include<iostream>
using namespace std;
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    int t;cin>>t;
    while(t--)
    {
        int a,b;
        cin>>a>>b;
        cout<<gcd(a,b)<<endl;
    }
}

BFS走迷宫类型

一般bfs tle了就说明是没有判断有没有走过该路径

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 110;
char g[N][N];
int dx[4] = { -1,0,1,0 }, dy[4] = { 0,1,0,-1 };
int sx, sy, ex, ey, n;
#define pii pair<int,int>
int d[N][N];
int bfs()
{
    memset(d,-1,sizeof d);
    queue<pii>q;
    q.push({ sx,sy });
    d[sx][sy] = 0;
    while (q.size())
    {
        auto p = q.front(); q.pop();
        int x = p.first, y = p.second;
        for (int i = 0; i < 4; i++)
        {
            int tx = x + dx[i], ty = y + dy[i];
            if (tx>=1&&tx<=n&&ty>=1&&ty<=n&&g[tx][ty]!=g[x][y]&&d[tx][ty]==-1)
            {
                q.push({ tx,ty });
                d[tx][ty] = d[x][y]+1;
                if (tx == ex && ty == ey)
                    return d[tx][ty];
            }
        }
    }
    return -1;
}
int main()
{
    cin >> n; char ch;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {
            cin >> ch;
            if (ch == ' ')
                cin >> ch;
            g[i][j] = ch;
            if (g[i][j] == 'A')
                sx = i, sy = j;
            if (g[i][j] == 'B')
                ex = i, ey = j;

        }
    cout << bfs() << endl;
}

砝码称重 DP+记忆化搜索剪枝暴搜

#include<iostream>
#include <unordered_map>
using namespace std;
const int N = 110;
const int M=2e5+10;
bool meo[N][M];
bool ans[M];
int n,cnt;
int a[N];
/*
加了剪枝的暴搜
当遇到u和sum相同的状态时可以停止向前递归搜索了
因为已经搜过一次 后续是重复搜索(可以提高时间效率)
深搜的三个路径分别是
(我们假设a-b为左边的砝码重量减去右边的砝码重量)
1.第i个砝码选择不放 u+1,sum
2.第i个砝码选择放在右边 u+1,sum-a[i]
又因为当sum为负时,我们可以颠倒砝码的位置来得到这种状态。
所以可以是u+1,abs(sum-a[i])
3.第i个砝码选择放在左边 u+1,sum+a[i]
*/
void dfs(int u,int sum)
{
    if(meo[u][sum])return;
    meo[u][sum]=true;
    if(u==n&&!ans[sum])
    {
       cnt++;
       ans[sum]=true;
       return;
    }
    else
    {
        dfs(u+1,sum);
        dfs(u+1,abs(sum-a[u]));
        dfs(u+1,sum+a[u]);
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    cin>>a[i];
    dfs(0,0);
    cout<<cnt-1<<endl;
}
#include<iostream>
using namespace std;
const int N=110;
const int M=2e5+10;
int a[N];
int f[N][M];
int main()
{
    int n;cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
    cin>>a[i];
    sum+=a[i];
    }
    f[0][0]=1;
    //将考虑第0个砝码 并且总和为0的状态视为递推的地基
    /*
    集合f[i][j]代表的是该种方案是否存在
    i代表的第i个砝码,j代表的是当前左边-右边的总和
    因此状态的转移可以分为三种
    1.f[i][j]=f[i-1][j]   第i个砝码不放
    2.f[i][j]=f[i-1][j+a[i]]  第i个砝码放到了右边
    3.f[i][j]=f[i-1][abs[j-a[i]] 第i个砝码放到了左边
    当第i-1个状态的sum为负时 我们可以将两边砝码颠倒
    这样同样能得到 abs[j-a[i]]的状态 这时再在颠倒的状态下将砝码放到右边
    从而也可以得到f[i][j]的状态
    总的来说我们只要从以上三种状态取其中一种存在的状态
    即可得到当前f[i][j]状态
    */
    for(int i=1;i<=n;i++)
    for(int j=0;j<=sum;j++)
    {
        f[i][j]=f[i-1][j]||f[i-1][j+a[i]]||f[i-1][abs(j-a[i])];
    }
    int ans=0;
    for(int i=1;i<=sum;i++)
    if(f[n][i])ans++;
    cout<<ans<<endl;
}

最大公约数

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
const int N=1e5+10;
int a[N];
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    cin>>a[i];
    sort(a+1,a+1+n);
    int d=0;//0与b取gcd为b
    for(int i=2;i<=n;i++)
    {
       d=gcd(d,a[i]-a[0]);
    }
    /*求一组数据的最大公约数,只需要先求前两个数的最大公约数d
    然后拿d和后面的数求最大公约数并更新
    */
    cout<<(a[n]-a[1])/g+1<<endl;
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Nathan Qian

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

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

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

打赏作者

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

抵扣说明:

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

余额充值