题意:算出最小生成树的总边权和乘上不同最小生成树的个
题目给的生成随机数通过异或和位移 , 每次生成不同的32位, 周期为2的32次方减1。
重边的概率很小
也就是最小生成树如果有的话只有一个。
跑一遍Kruskal即可
/*************************************************************************
> File Name: xuzhouA.cpp
> Author: Hcacai
> Created Time: 2019年10月27日 星期日 12时45分51秒
************************************************************************/
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
using namespace std;
const int mod=1e9+7;
const int N=2e5+100;
typedef unsigned long long ll;
unsigned long long k1, k2;
int tot; //边的数目
struct edge{
ll u, v, w;
}e[N]; //边
int f[N]; //并查集
bool cmp( edge e1, edge e2 )
{
return e1.w<e2.w;
}
void add(ll u, ll v, ll w)
{
e[tot].u=u;
e[tot].v=v;
e[tot++].w=w;
}
unsigned long long xorShift128Plus() {
unsigned long long k3 = k1, k4 = k2;
k1 = k4;
k3 ^= k3 << 23;
k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
return k2 + k4;
}
int n,m;
void gen(){
scanf("%d%d%llu%llu", &n, &m, &k1, &k2);
for(int i = 1; i <= m; ++i) {
ll u = xorShift128Plus() % n + 1;
ll v = xorShift128Plus() % n + 1;
ll w = xorShift128Plus();
add(u,v,w);
add(v,u,w);
}
}
ll Find(ll x) //查找跟节点
{
if(f[x]==-1) return x;
return f[x]=Find(f[x]);
}
ll kruskal()
{
sort(e,e+tot, cmp);
memset(f,-1,sizeof(f));
ll ans=0, sum=0;
for(int i=0; i<tot; i++)
{
ll u=e[i].u;
ll v=e[i].v;
ll w=e[i].w;
ll t1=Find(u);
ll t2=Find(v);
if(t1!=t2)
{
ans=(ans+w)%mod;
f[t1]=t2;
sum++;
}
if(sum == n-1) break; //边的数目
}
if(sum<n-1) return 0;
return ans%mod;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
tot=0;
gen();
ll ans=kruskal();
printf("%lld\n", ans);
}
return 0;
}