刷题记录(NC235611 牛牛国的战争,NC23803 DongDong认亲戚,NC235622 叠积木)

NC235611 牛牛国的战争

题目链接

关键点

1、因为要在能击败所有敌军的基础下,求存活最多的数量,那么我们可以对敌军的防御力从大到小排列,对于友军的攻击力从大到小排列,这样遍历一次敌军,将所有可以击败该敌军的友军防御力存入multiset,因为防御力可能会重复

2、对于多个可以击败敌军的友军,我们挑选那个刚刚好可以击败敌军且存活的,如果没有,那么横竖都为失去一个友军,干脆失去那个防御力最低的

3、对于存活的计算,我们再选择友军时,可能所有的友军不会都加入set中,因此最后要加上,同样的set里的所有元素不一定都会上场,也得加上

完整代码

# include <cstdio>
# include <iostream>
# include <set>
# include <algorithm>
using namespace std;
const int N = 100000+10;
int t, n, m;
multiset<int>s;
struct fri{
    int g, f;
}f[N];
struct di{
    int g, f;
}d[N];
bool cmp1(fri f1, fri f2)
{
    return f1.g>f2.g;
}
bool cmp2(di d1, di d2)
{
    return d1.f>d2.f;
}
int main()
{
    cin>>t;
    for (int k=1; k<=t; k++)
    {
        s.clear();
        cin>>n>>m;
        for (int i=1; i<=n; i++)
        {
            cin>>f[i].g>>f[i].f;
        }
        
        for (int i=1; i<=m; i++)
            cin>>d[i].g>>d[i].f;
        sort(f+1, f+1+n, cmp1);
        sort(d+1, d+1+m, cmp2);
        int pos = 1, ans = 0, flag = 0;
        for (int i=1; i<=m; i++)
        {
            while (f[pos].g>=d[i].f && pos<=n)
            {
//                 cout<<f[pos].g<<" "<<d[i].f<<endl;
                s.insert(f[pos].f);
                pos++;
            }
            if (s.size()==0)
            {
                flag = 1;
                cout<<"Case #"<<k<<": -1"<<endl;
                break;
            }
            auto it = s.upper_bound(d[i].g);
            if (it!=s.end())
            {
                ans++;
                s.erase(it);
            }
            else
            {
                s.erase(s.begin());
            }
//             cout<<s.size()<<endl;
        }
//         cout<<ans<<" "<<s.size()<<" "<<pos<<endl;
        if (!flag)
           cout<<"Case #"<<k<<": "<<ans+s.size()+n+1-pos<<endl;
    }
    
    
    return 0;
}

NC23803 DongDong认亲戚

题目链接

关键点:

1、利用map来使名字对应数字,然后直接上并查集

完整代码

# include <cstdio>
# include <iostream>
# include <map>
using namespace std;
const int N = 200000+10;
int n, m;
int fa[N];
map<string, int>mp;
int find(int x)
{
    return (x==fa[x])? x: fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
    fa[find(x)] = find(y);
}
int main()
{
    for (int i=0; i<N; i++)
        fa[i] = i;
    cin>>n>>m;
    for (int i=1; i<=n; i++)
    {
        string s;
        cin>>s;
        mp[s] = i;
    }
    for (int i=1; i<=m; i++)
    {
        int x;
        string a, b;
        cin>>x>>a>>b;
        if (x==2)
        {
            int f1 = find(mp[a]), f2 = find(mp[b]);
            if (f1==f2)
                cout<<"1"<<endl;
            else
                cout<<"0"<<endl;
        }
        else
        unite(mp[a], mp[b]);
    }
    
    
    return 0;
}

NC235622 叠积木

题目链接

关键点:

1、我们用一个fa数组存每个积木的父亲(设为该积木的最底下的积木),一个d数组存每个积木到最底下有多少个积木,一个cnt数组存该积木一共有多少(下标为最底下的积木)

2、对于每一次的搭建,比如从x->y,先找到x的父亲fx,y的父亲fy,判断不相等后将

fa[fx] = fy,d[fx] = cnt[fy](当前x父亲(即x最底下的积木距离此时的父亲结点(fy)的距离为y积木的数量)), cnt[fy]+=cnt[fx](y积木的数量加上x积木的数量)

3、对于find,除了fa[x] = find(fa[x]);还有d[x] += d[fa[x]],不断更新该积木与父亲的距离

完整代码

# include <iostream>
# include <cstdio>
using namespace std;
const int N = 30000+10;
int n;
int fa[N], d[N], cnt[N];
int find(int x)
{
    if (fa[x]!=x)
    {
        int t = find(fa[x]);
        d[x] += d[fa[x]];
        fa[x] = t;
    }
    return fa[x];
}
void unite(int x, int y)
{
    int f1 = find(x), f2 = find(y);
    if (f1!=f2)
    {
        fa[f1] = f2;
        d[f1] = cnt[f2];
        cnt[f2] += cnt[f1];
    }
}
int main()
{
    cin>>n;
    for (int i=1; i<=N; i++)
    {
        fa[i] = i;
        d[i] = 0;
        cnt[i] = 1;
    }
    for (int i=1; i<=n; i++)
    {
        char c;
        cin>>c;
        if (c=='M')
        {
            int x, y;
            cin>>x>>y;
            unite(x, y);
        }
        else
        {
            int x;
            cin>>x;
            find(x);
            cout<<d[x]<<endl;
        }
    }
    
    
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值