hdu6411—带劲的and和(2018百度之星复赛)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jiangzhiyuan123/article/details/81989386

题目链接:传送门

 

带劲的and和

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 219    Accepted Submission(s): 113

Problem Description

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

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

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

度度熊想知道求出:

\sum_{i=1}^{n}\sum_{n-1}^{j=i+1}f(i,j)*max(v_{i},v_{j})*(v_{i}\wedge v_{j})
(^表示&)其中&是C++中的and位运算符,如1&3=1, 2&3=2。

请将答案对109+7取模后输出。

Input

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

每组数据第一行两个整数n,m;第二行n个数表示vi;接下来m行,每行两个数u,v,表示点u和点v之间有一条无向边。**可能有重边或自环。**

数据组数T=50,满足:

- 1≤n,m≤100000
- 1≤vi≤109。

其中90%的数据满足n,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

99

 

解题思路:

1.对于f(i,j),若i,j在图中的联通块内,则f(i,j)=1,所以一个一个联通块来计算表达式的值。

2.对于max(vi,vj),枚举一个联通块中结点的最大值,对结点数值排序,这样能快速计算有多少对结点的max(vi,vj)为我们当前枚举的对象。

3.对于(vi&vj),从第二步我们枚举了一个数值vx,我们只需要计算max(vi,vj) = vx的结点对中对vx二进制位为1的贡献,举个例子。对于max(3,5) = 5,5的二进制表示为101,3的二进制表示为11,则3对5的首位贡献为1。之前对联通块中结点的数值排了序,这里从小到大计算结点对数对枚举的vx的贡献。

时间复杂度为0(nlogn+30*n)

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <ctime>

using namespace std;

typedef long long llt;

const int INF = 0x3fffffff;
const int N = 100010;
const double pi = acos(-1);
const int mod = 1e9+7;

struct Edge{
    int node;
    Edge*next;
}edge[N*2];
Edge*head[N];
int Ecnt,vis[N],val[N],bia[40];
vector<llt>vec;

void init()
{
    Ecnt = 0;
    memset(vis,0,sizeof(vis));
    fill(head,head+N*2,(Edge*)0);
}

void mkEdge(int a,int b)
{
    edge[Ecnt].node = b;
    edge[Ecnt].next = head[a];
    head[a] = edge+Ecnt++;
}

void dfs(int u)
{
    vis[u] = 1;
    vec.push_back(val[u]);
    for(Edge*p = head[u]; p; p = p->next){
        int v = p->node;
        if(vis[v]) continue;
        dfs(v);
    }
}

llt solve()
{
    memset(bia,0,sizeof(bia));
    sort(vec.begin(),vec.end());
    llt ans = 0;
    for(int i = 0; i < vec.size(); ++i){
        int cnt = 0; llt temp = vec[i];
        while(temp){
            if(temp&1){
                llt a = bia[cnt],b = 1<<cnt;
                ans = (ans+vec[i]*a%mod*b%mod)%mod;
                bia[cnt]++;
            }
            temp >>= 1;
            cnt++;
        }
    }
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        init();
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; ++i) scanf("%d",&val[i]);
        int a,b;
        for(int i = 0; i < m; ++i){
            scanf("%d%d",&a,&b);
            mkEdge(a,b);
            mkEdge(b,a);
        }
        llt ans = 0;
        for(int i = 1; i <= n; ++i){
            if(vis[i]) continue;
            vec.clear();
            dfs(i);
            ans = (ans+solve())%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

猜你喜欢

转载自blog.csdn.net/jiangzhiyuan123/article/details/81989386