2021 ICPC 沈阳站 B. Bitwise Exclusive-OR Sequence(亦或,位运算,菊花图)

44 篇文章 0 订阅
13 篇文章 0 订阅

2021 ICPC 沈阳站

B. Bitwise Exclusive-OR Sequence

分析:

  • 图由链和环构成

    • 考虑环: 从一个点开始到这个点结束的亦或和为0(因为每个点权都用了两次),就是说:若出现环,且环的亦或和不为0,就输出 “-1”

    • 考虑链:从链的一端出发 设 ( a 1 , a 2 , . . . , a n ) (a_1,a_2,...,a_n) (a1,a2,...,an) 为链上的点权

      a 1 ∧ a 2 = w 1 a_1\land a_2=w_1 a1a2=w1

      a 2 ∧ a 3 = w 2 a_2\land a_3=w_2 a2a3=w2

      . . . ... ...

      a n − 1 ∧ a n = w n − 1 a_{n-1}\land a_n=w_{n-1} an1an=wn1

      转换一下:

      a 1 ∧ a 2 = w 1 a_1\land a_2=w_1 a1a2=w1

      a 1 ∧ a 3 = w 1 ∧ w 2 a_1\land a_3=w_1\land w_2 a1a3=w1w2

      . . . ... ...

      a 1 ∧ a n = w 1 ∧ w 2 ∧ . . . ∧ w n − 1 a_1\land a_n=w_1\land w_2 \land ... \land w_{n-1} a1an=w1w2...wn1

    • 转换到上述形式,可以发现只需确定任意一点权便可求出所有的点权

      令上述亦或和分别为: s 1 , s 2 , . . . , s n − 1 s_1,s_2,...,s_{n-1} s1,s2,...,sn1 ;再移一下项

      a 2 = s 1 ∧ a 1 a_2=s_1\land a_1 a2=s1a1

      a 3 = s 2 ∧ a 1 a_3=s_2\land a_1 a3=s2a1

      . . . ... ...

      a n = s n − 1 ∧ a 1 a_n=s_{n-1}\land a_1 an=sn1a1

  • 题目要求的是 ∑ i = 1 n a i \sum_{i=1}^na_i i=1nai 的最小值,s 已知,确定 a 1 a_1 a1 即可

    • 考虑枚举 a 1 a_1 a1 1 e 9 1e9 1e9 直接炸
    • 思路转换:逐位确定 a 1 a_1 a1 的每一位
  • 将某一连通分量的所有点直接与 a 1 a_1 a1 相连,就变成了一个菊花图

反思:

  • 赛时就卡在思路转换这一步卡了一个多小时,没有在草稿纸上进行演算,就口胡加想想,甚至都要放弃了,最后发现过了两百多了,无奈继续硬着头皮去看 T_T

    还是题写太少了

DFS

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

const int N=1e5+5;
vector <pair<int,int> > g[N];
int flag=1,vis[N];
int f[N];
vector <int> res[N]; 
void dfs(int st,int u)
{
    vis[u]=1;
    for(auto t : g[u])
    {
        int v=t.first, w=t.second;
        if(vis[v]) //成环了
        {
            if(f[v]!=(f[u]^w)) flag=0;
        }
        else 
        {
            f[v]=f[u]^w;
            res[st].push_back(v);
            dfs(st,v);
        }
    }
}
int cnt[55];
int add(int st)
{
    memset(cnt,0,sizeof(cnt));
    int len=res[st].size();
    int x=0;
    for(int j=0;j<30;j++)
    {
        for(int v : res[st])
        {
            if((f[v]>>j)&1) cnt[j]++;
        }
        if(cnt[j]>len/2) x+=(1<<j); // 当前位的1的个数超过len/2,那么a1的当前位取1更优
    }
    int ans=x;
    for(int v : res[st]) ans+=f[v]^x;
    return ans;
}
signed main()
{
    ios_base::sync_with_stdio(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        g[u].push_back({v,w});
        g[v].push_back({u,w});
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(!vis[i] && flag)
        {
            dfs(i,i);
            ans+=add(i);
        }
    }
    if(flag) cout<<ans<<"\n";
    else cout<<"-1\n";
}

BFS

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

const int N=1e5+5;
vector <pair<int,int> > g[N];
vector <int> ans[N];
int vis[N],f[N];
int flag=1;
void bfs(int st)
{
    queue <int> q;
    q.push(st);
    vis[st]=1;
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        for(auto t : g[u])
        {
            int w=t.second,v=t.first;
            if(vis[v])
            {
                if(f[v]!=(f[u]^w)) flag=0;
            }
            else 
            {
                vis[v]=1;
                f[v]=f[u]^w;
                ans[st].push_back(v);
                q.push(v);
            }
        }
    }
}
int cnt[55];
int add(int st)
{
    memset(cnt,0,sizeof(cnt));
    int len=ans[st].size();
    int x=0;
    for(int j=0;j<30;j++)
    {
        for(int v : ans[st])
        {
            int t=f[v];
            if((t>>j)&1) cnt[j]++;
        }
        if(cnt[j]>len/2) x+=(1<<j);
    }
    int ans1=x;
    for(int v : ans[st]) ans1+=f[v]^x;
    return ans1;
}
signed main()
{
    ios_base::sync_with_stdio(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        g[u].push_back({v,w});
        g[v].push_back({u,w});
    }
    int ans1=0;
    for(int i=1;i<=n;i++)
    {
        if(flag && !vis[i])
        {
            bfs(i);
            int t=add(i);
            ans1+=t;
        }
    }
    if(flag) cout<<ans1<<endl;
    else cout<<-1<<endl;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yezzz.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值