蒟蒻的2023蓝桥

看题居然把数据范围的优先级看的很低,很多问题可能很难解决,但是数据小,优雅一点的暴力就能做。

另外数据范围也能提示你用什么算法。

A.日期统计

没有意识到后面的2023统计的日期会与前面的重复。

另外dfs写的时候脑袋晕晕的框架都有点想不清,实际上就八个位置,100种可能。

所以dfs以深度来看。

B.01串的熵

直接跳过了。。

实际上直接枚举就行,另外注意精度1e-4,以及知道log2函数

C.冶炼金属

每条记录计算最大值与最小值,最后为了满足所有记录,取每个最大值中的最小值,取每个最小值中的最大值。

另一种做法,二分。

求满足所有记录的最大值与最小值。

二分求取满足要求的值时,可以转化为求大于等于要求的最小值(或相反),同时二分的check值与mid的对应关系还是要看的hh。

当答案很好验证时,都可以试试二分。

D.飞机降落

数据范围很小,全排列加一点点贪心的决策。

E.接龙数列

我们无法得知每个数是否需要删除,那么则需要讨论来判断,dp的感觉。

线性dp

f[i][j]表示考虑前i个数结尾为j的最小删除次数,尽管是简单的dp,我写起来还是很吃力,初始化0维为0表示兼容,记住了。

F.岛屿个数

被完全的框住意味着无论是直线还是斜角都没法走过来。

考试时只会走直线,导致错误。

题解的优雅解法,在外围套一圈0,从一个点开始向8个方向搜0就行,另外不用像我那样,将接触的1全部标记起来。

搜完后留下的空洞即岛屿。

在考试中还是聪明了一点,没有像之前那样搜索加并查集,直接循环如果没走过就搜就行了,st数组标记一下走过的地方,经典的搜索连通块方式。。。

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
typedef long long LL;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;

const int N=55;
char g[N][N];
bool st[N][N];
int n,m;

//0,0没关系,已经走过了,可以枚举9宫格 优雅
int dx9[]={-1,0,1},dy9[]={-1,0,1};
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};

void dfs0(int x,int y){
    st[x][y]=true;
    for(int i=0;i<3;i++){
        for(int j=0;j<3;j++){
            int a=x+dx9[i],b=y+dy9[j];
            if(a>=0&&a<=n+1&&b>=0&&b<=m+1&&g[a][b]=='0'&&!st[a][b]){
                dfs0(a,b);
            }
        }
    }
}

void dfs2(int x,int y){//把空洞填满
    st[x][y]=true;
    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&&!st[a][b]){
            dfs2(a,b);
        }
    }
}

void solve(){
    cin>>n>>m;
    memset(g,0,sizeof g);
    memset(st,0,sizeof st);
    for(int i=1;i<=n;i++)cin>>g[i]+1;//外圈套0
    for(int i=0;i<=n+1;i++)g[i][m+1]=g[i][0]='0';
    for(int i=0;i<=m+1;i++)g[n+1][i]=g[0][i]='0';
    dfs0(0,0);
    int res=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!st[i][j]){
                dfs2(i,j);
                res++;
            }
        }
    }
    cout<<res<<endl;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

G.子串简写

本质是快速判断距离c1大于等于k-1的c2有多少个。

做法一:记录c2的位置,枚举c1,二分查找距离大于等于k-1的下标,末下标减去下标得到个数

做法二:后缀和,毕竟只需要查看某个区间有多少个c2罢了

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
typedef long long LL;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;

const int N=5e5+10;
int cnt[N];

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int k;
    cin>>k;
    string s;
    char a,b;
    cin>>s>>a>>b;
    for(int i=s.size()-1;~i;i--){
        cnt[i]=(s[i]==b);
        cnt[i]+=cnt[i+1];
    }
    LL res=0;
    for(int i=0;i<s.size();i++){
        if(s[i]==a&&i+k-1<s.size())res+=cnt[i+k-1];
    }
    cout<<res<<endl;
    return 0;
}

 

H.整数删除

双链表+优先队列/set+模拟

记住优先队列与set等价(用法上),priority_queue多提供了一个弹出队头,访问队头,set也能实现只是麻烦一点,但是set支持任意删除(根据value或地址)。

补:优先队列能够允许重复元素存在,set不行

所以如果不需要队头,那么可以直接使用set。

set的逆序初始化:set<int,greater<int>> 访问队头*S.begin 删除队头S.erase(S.begin())。

收获:priority_queue 也能O1进行任意删除,只要再加另一个优先队列,将要删除的元素存入其中,当2个优先队列的top()相等时,2个都pop()。

set与priority_queue的修改操作,二者都不能直接修改元素,只能通过间接的方法来修改,即删除再添加。

priority_queue的写法(set简单修改即可)

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<LL,int> PLI;

const int INF=0x3f3f3f3f;

const int N=5e5+10;
int l[N],r[N],idx;
LL e[N];
int n,k;
priority_queue<PLI,vector<PLI>,greater<PLI>>q,re;//value and id

void init(){
    l[1]=0,r[0]=1;
    idx=2;
}

void insert(int k,int x){
    e[idx]=x;
    l[idx]=k,r[idx]=r[k];
    l[r[k]]=idx,r[k]=idx++;
}

void remove(int k){
    //需要特判边界
    if(l[k]!=0){
        re.emplace(e[l[k]],l[k]-1);
        e[l[k]]+=e[k];
        q.emplace(e[l[k]],l[k]-1);
    }
    if(r[k]!=1){
        re.emplace(e[r[k]],r[k]-1);
        e[r[k]]+=e[k];
        q.emplace(e[r[k]],r[k]-1);
    }
    
    l[r[k]]=l[k],r[l[k]]=r[k];
    //2步合起来就是修改
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    init();
    cin>>n>>k;
    //md idx与i对应好好的 idx=i+1 没变动 不需要fidx[]来记录 
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        insert(l[1],x);
        q.emplace(x,i);
    }
    while(k--){
        while(re.size()&&re.top()==q.top())re.pop(),q.pop();
        auto [x,id]=q.top();
        q.pop();
        remove(id+1);
    }
    for(int i=r[0];i!=1;i=r[i])cout<<e[i]<<' ';
    return 0;
}

 

I.景区导游

写了floyd暴力,不知道是否正确。

正解待补---lca。

J.砍树

输出样例。。。

 正解待补---lca。

posted @ 2023-04-09 09:34  星陨光逝  阅读(7)  评论(0编辑  收藏  举报