Codeforces Round #805 (Div. 3)

E. Split Into Two Sets

题目描述:

给定n对含有两个多米诺牌的数对,问能不能拆分成两套含有1-n的多米诺骨牌?

主要思路:

赛时觉得应该先转化成图,然后利用并查集来做,两套f数组,看看是不是能分成n/2堆?
然后就wa2了…
看了dalao的代码,才发现这是一道二分图染色的问题

#include<iostream>
#include<algorithm>
#include<vector>
#include<unordered_map>
using namespace std;
vector<int> a[200010];
unordered_map<int,int> book,num;
bool find(int x,int k)
{
    if(!book[x])
        book[x]=k;
    else
    {
        if(book[x]==k) return 1;
        else return 0;
    }
    for(int i=0;i<a[x].size();i++)
    {
        int now=a[x][i];
        if(!find(now,3-k)) return 0;
    }
    return 1;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        book.clear();
        num.clear();
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            int x,y;
            cin>>x>>y;
            num[x]+=1;
            num[y]+=1;
            a[x].push_back(y);
            a[y].push_back(x);
        }
        bool flag=1;
        for(int i=1;i<=n;i++)
        {
            if(!book[i])
            {
                if(!find(i,1))
                {
                    flag=0;
                }
            }
            if(num[i]!=2)
            {
                flag=0;
            }
            a[i].clear();
        }
        if(flag) cout<<"YES\n";
        else cout<<"NO\n";
    }
    return 0;
}

F. Equate Multisets

题目描述:

给两个集合{a},{b},问能不能通过对b中的元素*2,/2来使a=b?

主要思路:

虽然题目上说不能对a进行操作,但是我们可以将是偶数的a/2 == (bx2=a)
所以,我们先将所有的是偶数的a/2变为奇数。
然后,就只需要对b考虑/2操作即可,无需再考虑x2,因为a里全是奇数,b*2一定为偶数。

#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
unordered_map<int,int> book;
int a[200010],b[200010];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        book.clear();
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            while(a[i]%2==0&&a[i])
                a[i]/=2;
            book[a[i]]+=1;
        }
        for(int i=1;i<=n;i++)
        {
            cin>>b[i];
            while(b[i]%2==0&&b[i])
                b[i]/=2;
            while(b[i])
            {
                if(book[b[i]])
                {
                    book[b[i]]-=1;
                    break;
                }
                else b[i]/=2;
            }
        }
        bool flag=1;
        for(int i=1;i<=n;i++)
            if(book[a[i]])
            {
                flag=0;
                break;
            }
        if(flag) cout<<"YES\n";
        else cout<<"NO\n";
    }
    return 0;
}

G. Passable Paths

题目描述:

给出一颗树,每次询问给出若干个点,要求这若干个点是否在同一条链上.

主要思路:

先找到深度最大的两个点为链的两个端点,然后利用lca判断其他点是否在链上。

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<cstring>
using namespace std;
const int N=2e5+10;
int n;
int depth[N];
int fa[N][30];
vector<int> l[N];
int a[N];
void bfs(int x)
{
    memset(depth,0x3f,sizeof depth);
    depth[1]=1;
    depth[0]=0;
    queue<int> q;
    q.push(1);
    while(q.size())
    {
        int now=q.front();
        q.pop();
        for(int i=0;i<l[now].size();i++)
        {
            int ne=l[now][i];
            if(depth[ne]>depth[now]+1)
            {
                depth[ne]=depth[now]+1;
                q.push(ne);
                fa[ne][0]=now;
                for(int k=1;k<=17;k++)
                    fa[ne][k]=fa[fa[ne][k-1]][k-1];
            }
        }
    }
}
int lca(int x,int y)
{
    if(depth[x]<depth[y]) swap(x,y);
    // 处理到同一深度
    for(int k=17;k>=0;k--)
    {
        if(depth[fa[x][k]]>=depth[y])
            x=fa[x][k];
    }
    if(x==y) return x;
    for(int k=17;k>=0;k--)
    {
        if(fa[x][k]!=fa[y][k])
        {
            x=fa[x][k];
            y=fa[y][k];
        }
    }
    return fa[x][0];
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int x,y;
        cin>>x>>y;
        l[x].push_back(y);
        l[y].push_back(x);
    }
    bfs(1);
    int q;
    cin>>q;
    while(q--)
    {
        int m;
        cin>>m;
        for(int i=1;i<=m;i++) cin>>a[i];
        int d1=0,d2=0;
        for(int i=1;i<=m;i++)
        {
            if(depth[a[i]]>depth[d1])
                d1=a[i];
        }
        for(int i=1;i<=m;i++)
        {
            if(depth[a[i]]>depth[d2]&&lca(d1,a[i])!=a[i])
                d2=a[i];
        }
        bool flag=1;
        int p=lca(d1,d2);
        // cout<<d1<<' '<<d2<<' '<<p<<endl;
        for(int i=1;i<=m;i++)
        {
            int now1=lca(d1,a[i]);
            int now2=lca(d2,a[i]);
            // cout<<now<<endl;
            if(!(now1==a[i]&&now2==p||now1==p&&now2==a[i]))
            {
                flag=0;
                break;
            }
        }
        if(flag) cout<<"YES\n";
        else cout<<"NO\n";
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值