蓝桥杯刷题十

1.三体攻击

这题如果映射到一维的情况下,就是一维差分加二分,那现在就是三维差分加二分了这是第一个难点。

第二个难点就是,坐标要映射一下,因为内存只允许开一维的空间,三维是不可能的。

写法有点复杂 考验码力。

#include <bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int A,B,C,m;
int s[N],b[N],bp[N];
int op[N/2][7];
int d[8][4]={
    {0,0,0,1},
    {0,0,1,-1},
    {0,1,0,-1},
    {0,1,1,1},
    {1,0,0,-1},
    {1,0,1,1},
    {1,1,0,1},
    {1,1,1,-1},
};
int get(int i,int j,int k)
{
    return (i*B+j)*C+k;
}
bool check(int mid)
{
    memcpy(b,bp,sizeof b);
    for(int i=1;i<=mid;i++)
    {
        int h=op[i][6];
        int x1=op[i][0],x2=op[i][1];
        int y1=op[i][2],y2=op[i][3];
        int z1=op[i][4],z2=op[i][5];
        b[get(x1,y1,z1)]-=h;
        b[get(x1, y1, z2 + 1)] += h;
        b[get(x1, y2 + 1, z1)] += h;
        b[get(x1, y2 + 1, z2 + 1)] -= h;
        b[get(x2 + 1, y1, z1)] += h;
        b[get(x2 + 1, y1, z2 + 1)] -= h;
        b[get(x2 + 1, y2 + 1, z1)] -= h;
        b[get(x2 + 1, y2 + 1, z2 + 1)] += h;
    }
    memset(s, 0, sizeof s);
    for (int i = 1; i <= A; i ++) {
        for (int j = 1; j <= B; j ++) {
            for (int k = 1; k <= C; k ++) {
                s[get(i, j, k)] = b[get(i, j, k)];
                for (int u = 1; u < 8; u ++ ) {
                    int x = i - d[u][0];
                    int y = j - d[u][1];
                    int z = k - d[u][2];
                    int t = d[u][3];
                    s[get(i, j, k)] -= s[get(x, y, z)] * t;
                }

                if (s[get(i, j, k)] < 0) {
                    return true;
                }
            }
        }
    }

    return false;
}
int main()
{
    cin>>A>>B>>C>>m;
    for(int i=1;i<=A;i++)
        for(int j=1;j<=B;j++)
            for(int k=1;k<=C;k++)
                cin>>s[get(i,j,k)];
    for(int i=1;i<=A;i++)
        for(int j=1;j<=B;j++)
            for(int k=1;k<=C;k++)
            {
                for(int u=0;u<8;u++)
                {
                    int x=i-d[u][0];
                    int y=j-d[u][1];
                    int z=k-d[u][2];
                    int t=d[u][3];
                    bp[get(i,j,k)]+=s[get(x,y,z)]*t;
                }
            }
    for(int i=1;i<=m;i++)
        for(int j=0;j<7;j++){
            cin>>op[i][j];
        }
    int l=1,r=m;
    while(l<r)
    {
        int mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    cout<<r<<endl;
    return 0;
}

2.螺旋折线

这题看数据范围就知道是找规律了。但是规律比较难找。

可以用四种方式去划分线段,也可以用线性规划的方式划分线段,比如上方的线段就是

y>x&&y>=-x 以此类推

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    int x,y;
    cin>>x>>y;
    if(abs(x)<=y)
    {
        int n=y;
        cout<<(ll)(2*n-1)*(2*n)+x-(-n)<<endl;
    }
    else if(abs(y)<=x)
    {
        int n=x;
        cout<<(ll)(2*n)*(2*n)+n-y<<endl;
    }
    else if(abs(x)<=abs(y)+1&&y<0)
    {
        int n=abs(y);
        cout<<(ll)(2*n)*(2*n+1)+n-x<<endl;
    }
    else{
        int n=abs(x);
        cout<<(ll)(2*n-1)*(2*n-1)+y-(-n+1)<<endl;
    }
    return 0;
}

3.日志统计

双指针的模板应用题捏

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef pair<int,int> PII;
PII a[N];
int n,m,k;
bool st[N];
int cnt[N];
int main()
{
    cin>>n>>m>>k;
    for(int i=0;i<n;i++)
        cin>>a[i].first>>a[i].second;
    sort(a,a+n);
    for(int i=0,j=0;i<n;i++)
    {
        cnt[a[i].second]++;
        while(a[i].first-a[j].first>=m)
        {
            cnt[a[j].second]--;
            j++;
        }
        if(cnt[a[i].second]>=k)
            st[a[i].second]=true;
    }
    for(int i=0;i<N;i++)
        if(st[i])
        {
            cout<<i<<endl;
        }
    return 0;
}

4.献给阿尔吉侬的花束

BFS模板题!

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=210;
char g[N][N];
int n,m;
int sx,sy,ex,ey;
int dx[]={0,1,-1,0},dy[]={1,0,0,-1};
int dist[N][N];
int bfs()
{
    memset(dist,-1,sizeof dist);
    queue<PII> q;
    while(q.size())
        q.pop();
    q.push({sx,sy});
    dist[sx][sy]=0;
    while(q.size())
    {
        auto t=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int x=t.first+dx[i],y=t.second+dy[i];
            if(x<0||x>=n||y<0||y>=m)
                continue;
            if(g[x][y]=='#'||dist[x][y]!=-1)
            {
                continue;
            }
            dist[x][y]=dist[t.first][t.second]+1;
            if(ex==x&&ey==y)
                return dist[x][y];
            q.push({x,y});
        }
    }
    return -1;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            {
                cin>>g[i][j];
                if(g[i][j]=='S')
                    sx=i,sy=j;
                else if(g[i][j]=='E')
                    ex=i,ey=j;
            }
        int x=bfs();
        if(x==-1)
            cout<<"oop!"<<endl;
        else cout<<x<<endl;
    }
    return 0;
}

5.红与黑

flood filing捏

#include<iostream>
#include<cstring>
#include<queue>
#define x first
#define y second

using namespace std;
typedef pair<int,int> PII;

const int N=30;

char g[N][N];
int n,m;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
bool st[N][N];

int bfs(int x,int y)
{
    int cnt=1;
    queue<PII> q;
    q.push({x,y});
    while(q.size())
    {
        PII t=q.front();
        q.pop();
        int x=t.x,y=t.y;
        for(int i=0;i<4;i++)
        {
            int a=x+dx[i],b=y+dy[i];
            if(a<0 || a>=n || b<0 || b>=m) continue;
            if(st[a][b]) continue;
            if(g[a][b]!='.') continue;
            st[a][b]=true;
            q.push({a,b});
            cnt++;
        }
    }
    return cnt;
}


int main()
{
    while(cin>>m>>n,n||m)
    {
        memset(st,0,sizeof st);
        for(int i=0;i<n;i++) scanf("%s",g[i]);
        int x,y,flag=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
                if(g[i][j]=='@')
                {
                    x=i,y=j;
                    flag=1;
                }
            if(flag) break;
        }
        cout<< bfs(x,y) <<endl;
    }
    return 0;
}

6.交换瓶子

置换群解法 用一种特殊的方式画图

将a[i]往a[a[i]]连一条边 这样得到的图都是一些环 我们的目的就是得到n个环 然后交换两个元素不是增加一个环 就是减少一个环 我们的目的是变成n个环 那么答案就是n-k k为环的数量

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e5+5;
int a[N];
bool st[N];
int main(){
    int n;
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(!st[i]){
            cnt++;
            for(int j=i;!st[j];j=a[j]){//位置j指向a[j]的元素
                st[j]=true;
            }
        }
    }
    cout << n-cnt;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值