2024牛客寒假算法基础集训营2

题目B:防猫网

题目描述:

思路:比赛时做这个题时给我难毁兰,唉,直接用set把每一个猫的坐标存下来,去用4减去它的上,下,左,右,看看set中有没有存过,就行

#include<bits/stdc++.h>
using namespace std;
int n,m;
bool st[310][310];

int dx[]={-1,0,1,0},dy[]={0,1,0,-1};

set<pair<int,int>>S;

int main()
{
    
    int q;
    cin>>n>>m>>q;
    long long ans=0;
    while(q--)
    {
        int x,y;
        cin>>x>>y;
        int cnt=S.count({x-1,y})+S.count({x,y-1})+S.count({x+1,y})+S.count({x,y+1});
        S.insert({x,y});
        ans+=4-cnt;
    }
    cout<<ans<<endl;
    return 0;
}

 

题目F:消除宝石——>就是你有n个宝石,它们都有一个自己的颜色col,每一次,你可以选择一个颜色,把这个颜色的宝石最后出现的一个位置的宝石和它后面的宝石全部删去,问:最少需要几次操作能把所有宝石消完?

这里提供两种做法:1我们可以开n个vector存每一个宝石出现的位置,每次去找每个颜色的back,取一个最小,然后再进行删除操作,有删除的同时,我们去找下一个颜色的最小值,直到全部消完

                                2我们先开一个vis数组,记录每个颜色宝石出来的次数和一个cnt表示当前有多少个不同颜色的宝石,然后去从后向前来遍历这个数组,开一个map存当前的宝石出现的次数,用cnt1来记录当前这一段有多少个不同的颜色,用cnt2来记录被用完了颜色,想让操作最少,我们最优的操作一定是当已有的所有颜色都出现一遍之后我们就立刻直接消除操作:给操作次数++,让总的颜色cnt-用完的颜色cnt2就行

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5+10;
int a[N];

vector<int>col[N];//存储每一种颜色出现的下标

int main()
{
    int T;cin>>T;
    while(T--)
    {
        int n;cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            col[a[i]].push_back(i);
        }
        
        int ed=n,st=n,mn=n;
        
        for(int i=1;i<=n;i++)mn=min(mn,col[a[i]].back());
        
        long long ans=0;
        
        st=mn;
        while(ed>=1)
        {
            ans++;
            mn=st;
            for(int i=ed;i>=st;i--)
            {
                col[a[i]].pop_back();
                if(col[a[i]].size())mn=min(mn,col[a[i]].back());
            }
            ed=st-1,st=mn;
        }
        cout<<ans<<endl;
    }
    return 0;
}
#include<bits/stdc++.h>

using namespace std;

const int N = 2e5+10;
int a[N];
map<int,int>m;
int vis[N];

int main()
{
    int T;cin>>T;
    while(T--)
    {
        int n;cin>>n;
        int cnt=0,cnt1=0,cnt2=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            vis[a[i]]++;
            if(vis[a[i]]==1)cnt++;//共有多少个不同的颜色
        }
        
        long long ans=0;
        
        for(int i=n;i>=1;i--)
        {
            m[a[i]]++,vis[a[i]]--;
            if(m[a[i]]==1)cnt1++;//当前这一段出现了几个不同的颜色
            if(vis[a[i]]==0)cnt2++;//被用完的颜色
            if(cnt==cnt1)//存在的颜色都出现了一遍,那么当前这个位置就是最佳的
            {
                cnt-=cnt2;
                cnt1=cnt2=0;
                ans++;
                m.clear();
            }
        }
        
        cout<<ans<<endl;
        
    }
    return 0;
}

 题目I:Tokitsukaze and Short Path (plus)

 做法:我们遇到这种带公式的题,一定要想着把它展开,不然暴力算的话一定定会超时,我们把公式展开可以发现                        w[u][v] =2*max(a[u],a[v])   然后现在来考虑绕路,发现绝路一定会多一些路程的,所以直接这样算就行

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
long long a[N];
int main()
{
    int T;cin>>T;
    while(T--)
    {
        int n;cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n);
        long long ans=0;
        for(int i=n;i>=1;i--)
            ans+=2*a[i]*(i-1);
        
        cout<<ans*2<<endl;
        
    }
    return 0;
}

 题目J:Tokitsukaze and Short Path (minus)

与I题只是边权的计算方式不一样,把它展开之后我们可以发现:w[u][v]=2*min(a[u],a[v]) ,我们对a进行升序排序,可以发现在这个题是,有时绕路是比较优的,只与第一个相比就行

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5+10;

long long a[N];

int main()
{
    int T;cin>>T;
    while(T--)
    {
        int n;cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        
        sort(a+1,a+1+n);
        
        long long ans = 0;
                
        for(int i=1;i<=n;i++)ans+=min(4*a[1],2*a[i])*(n-i);
        
        cout<<ans*2<<endl;
        
    }
    return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值