2018“百度之星”程序设计大赛 - 复赛 1003 带劲的and和【位运算】

带劲的and和

 Accepts: 620

 Submissions: 1669

 Time Limit: 2000/1000 MS (Java/Others)

 Memory Limit: 65536/65536 K (Java/Others)

Problem Description

度度熊专门研究过“动态传递闭包问题”,他有一万种让大家爆蛋的方法;但此刻,他只想出一道简简单单的题——至繁,归于至简。

度度熊有一张n个点m条边的无向图,第ii个点的点权为v_iv​i​​。

如果图上存在一条路径使得点ii可以走到点jj,则称i,ji,j是带劲的,记f(i,j)=1f(i,j)=1;否则f(i,j)=0f(i,j)=0。显然有f(i,j) = f(j,i)f(i,j)=f(j,i)。

扫描二维码关注公众号,回复: 2847202 查看本文章

度度熊想知道求出: \sum_{i=1}^{n-1} \sum_{j=i+1}^{n} f(i,j) \times \max(v_i, v_j) \times (v_i \& v_j)∑​i=1​n−1​​∑​j=i+1​n​​f(i,j)×max(v​i​​,v​j​​)×(v​i​​&v​j​​)

其中\&&是C++中的and位运算符,如1&3=1, 2&3=2。

请将答案对10^9+710​9​​+7取模后输出。

Input

第一行一个数,表示数据组数TT。

每组数据第一行两个整数n,mn,m;第二行nn个数表示v_iv​i​​;接下来mm行,每行两个数u,vu,v,表示点uu和点vv之间有一条无向边。可能有重边或自环。

数据组数T=50,满足:

  • 1 \le n,m \le 1000001≤n,m≤100000
  • 1 \le v_i \le 10^91≤v​i​​≤10​9​​。

其中90%的数据满足n,m \le 1000n,m≤1000。

Output

每组数据输出一行,每行仅包含一个数,表示带劲的and和。

Sample Input

1
5 5
3 9 4 8 9 
2 1
1 3
2 1
1 2
5 2

Sample Output

Copy

99

思路:

分别计算每一个联通块内的值,可以直接bfs。计算时可以利用二进制的位进行运算。先排序,从前到后扫一遍,用一个bin数组记录每一个二进制位的1的出现次数,判断下一个值二进制中1的位置,然后从bin中相应位置取出运算就可以了。复杂度O(31*n)。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 100005
#define inf 0x3f3f3f3f3f3f3f3f
ll const mod = 1e9+7;
int n,m;
int bin[35];
ll val[MAXN],buf[MAXN];
vector<int> vec[MAXN];
bool vis[MAXN];
ll bfs(int st)
{
    int tot=0;
    queue<int> q;
    q.push(st);
    vis[st]=1;
    buf[tot++]=val[st];
    while(!q.empty())
    {
        int top=q.front(); q.pop();
        for(int i=0;i<vec[top].size();i++)
        {
            int v=vec[top][i];
            if(!vis[v])
            {
                vis[v]=1;
                buf[tot++]=val[v];
                q.push(v);
            }
        }
    }
    sort(buf,buf+tot);
    ll ret=0;
    memset(bin,0,sizeof bin);
    for(int i=0;i<tot-1;i++)
    {
        ll s=0;
        for(int j=0;buf[i];j++)
        {
            if(buf[i]&1) bin[j]++;
            buf[i]>>=1;
        }
        ll k=buf[i+1];
        for(int j=0;k;j++)
        {
            if(k&1)
            {
                s=(s+(ll)bin[j]*(1<<j))%mod;
            }
            k>>=1;
        }
        ret=(ret+buf[i+1]*s)%mod;
    }
    return ret;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",val+i);
        for(int i=1;i<=n;i++)
            vec[i].clear();
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            vec[u].push_back(v);
            vec[v].push_back(u);
        }
        memset(vis,0,sizeof vis);
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i]) ans=(ans+bfs(i))%mod;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013852115/article/details/81810898