2018 ICPC亞洲區域賽徐州站 A Rikka with Minimum Spanning Trees(求最小生成樹個數與總權值的乘積)


Hello everyone! I am your old friend Rikka. Welcome to Xuzhou. This is the first problem, which is a problem about the minimum spanning tree (MST). I promise you all that this should be the easiest problemeasiest problem for most people.

A minimum spanning tree, or minimum weight spanning tree, is a subset of edges from an edge-weighted undirected graph, which forms a tree with the minimum possible total edge weight that connects all the vertices together without any cycles.

In this problem, Rikka wants you to calculate the summation of total edge weights through all MSTs for a given graph, which obviously equals to the product of the total edge weight in an MST and the total number of different MSTs. Note that two spanning trees are different if the sets of their edges are different. In addition, a disconnected graph could have no MSTs, the number of whose different MSTs is zero.

To decrease the size of the input, Rikka provides an edge-weighted undirected graph via a random number generator with given random seeds, denoted by two integers k1 and k2. Supposing the number of vertices and edges in the graph are and m respectively, the following code in C++ tells you how to generate the graph and store the ii-th edge between the vertex u[i] and v[i] with weight w[i] in corresponding arrays. You can use the code directly in your submissions.

unsigned long long k1, k2;

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, u[100001], v[100001];
unsigned long long w[100001];

void gen() {
    scanf("%d%d%llu%llu", &n, &m, &k1, &k2);
    for(int i = 1; i <= m; ++i) {
        u[i] = xorShift128Plus() % n + 1;
        v[i] = xorShift128Plus() % n + 1;
        w[i] = xorShift128Plus();
    }
}

Also, to decrease the size of the output, your code should output the answer modulo (109+7).

If you have already learned how to handle that,If you have already learned how to handle that,start your show and omit all the rest of the statement.start your show and omit all the rest of the statement. 

To make sure everyone knows how to solve this problem, here Rikka would like to provide for you all an effective practice which can solve the problem and help you all get Accepted!

The first one you need to know is the Kirchhoff's matrix tree theorem. Given an undirected graph G with n vertices excluding all loops, its Laplacian matrix Ln×n is defined as (DA), where D is the degree matrix and A is the adjacency matrix of the graph. More precisely, in the matrix L the entry li,j (i≠j) equals to m where m is the number of edges between the i-th vertex and the j-th vertex, and Li,i equals to the degree of the i-th vertex. Next, construct a matrix L∗ by deleting any row and any column from L, for example, deleting row 1 and column 1. The Kirchhoff's matrix tree theorem shows that the number of spanning trees is exactly the determinant of L∗, which can be computed in polynomial time.

Now let me explain an algorithm that counts the number of MSTs. The algorithm breaks up the Kruskal's algorithm for MST into a series of blocks, each of which consists of a sequence of operations about adding edges in a same weight into a multigraph (where a multigraph is a graph, two vertices of which may be connected by more than one edge) whose vertices are components that have been built through the previous block of operations.

Precisely speaking, let's label the multigraph that has been built after the i-th block of operations as Gi. Without loss of generality, let's consider the 0-th block which has no operation and let G0 be an empty graph with n isolated vertices. The i-th block of operations squeezes vertices in Gi1 connected by edges in this block into a single vertex. The result is exactly the graph Gi.

If you know the cardinal principle of Kruskal's algorithm pretty well, you may find that the number of MSTs is the product of the numbers of spanning trees in every component of the graph for each block-defining weight. Actually, the number of edges for a certain weight is fixed in all MSTs, based on the greedy-choice strategy in Kruskal's algorithm. Finally, the Kirchhoff's matrix tree theorem helps you compute the numbers of spanning trees for graphs.

Input

The input contains several test cases, and the first line contains a single integer T (1≤T≤100), the number of test cases.

For each test case, the only line contains four integers n (1n105), m (m=105), k1 and k2 (108≤k1,k2≤1012), where k1 and k2 are chosen randomly except for the sample.

Output 

For each test case, output a single line with a single number, the answer modulo (109+7).

Note 

Since the generator code is only provided for C++, Rikka strongly suggests you all solve the problem using C or C++ instead of other programming languages.

Sample Input:

1
2 100000 123456789 987654321

Sample Output:

575673759

題意:

給你一個隨機函數,其中n為點的數量,m為邊的數量,該函數會自動初始化出一張無向無環圖,函數如下所示:

typedef unsigned long long ll;
ll k1,k2;
ll xorShift128Plus()
{
    ll k3=k1,k4=k2;
    k1=k4;
    k3^=k3<<23;
    k2=k3^k4^(k3>>17)^(k4>>26);
    return k2+k4;
}
void gen()
{
    scanf("%d%d%llu%llu",&n,&m,&k1,&k2);for(int i=1;i<=m;i++)
    {
        e[i].u=xorShift128Plus()%n+1;
        e[i].v=xorShift128Plus()%n+1;
        e[i].w=xorShift128Plus();
    }
}

利用如上所示隨機函數求出該圖所形成的最小生成樹個數與該最小生成樹總權值的乘積。

思路:

題面很長,很具有干擾性,當時看了很久才發現很多信息其實都是無效的,明白出題人用意后就發現題目很簡單。即求最小生成樹的個數與該最小生成樹總權值的乘積,不過要注意:如果沒有最小生成樹則輸出0;涉及較大數據量的變量要用unsigned long long表示。

#include<bits/stdc++.h>
#define MAX 100000
#define mod 1000000007
using namespace std;
typedef unsigned long long ll;
int n,m,p[MAX+5];
struct edge{
    int u,v;
    ll w;
}e[MAX+5];
int find(int r)
{
    if(p[r]!=r)    p[r]=find(p[r]);
    return p[r];
}
bool cmp(edge a,edge b)
{
    if(a.w!=b.w)return a.w<b.w;
    if(a.u!=b.u)return a.u<b.u;
    if(a.v!=a.v)return a.v<b.v; 
}
ll k1,k2;
ll xorShift128Plus()
{
    ll k3=k1,k4=k2;
    k1=k4;
    k3^=k3<<23;
    k2=k3^k4^(k3>>17)^(k4>>26);
    return k2+k4;
}
void gen()
{
    scanf("%d%d%llu%llu",&n,&m,&k1,&k2);
    for(int i=1;i<=n;i++)p[i]=i; 
    for(int i=1;i<=m;i++)
    {
        e[i].u=xorShift128Plus()%n+1;
        e[i].v=xorShift128Plus()%n+1;
        e[i].w=xorShift128Plus();
        if(e[i].u>e[i].v)
            swap(e[i].u,e[i].v);
    }
}
void kurskal()
{
    gen();
    sort(e+1,e+m+1,cmp);
    int cnt=0,i;
    ll cost=0,time=1,res;
    for(i=1;i<=m;i++)
    {
        int fu=find(e[i].u),fv=find(e[i].v);
        if(fu!=fv)
        {
            res=1;
            p[fu]=fv;
            cost+=e[i].w;
            cnt++;
            while(i+1<=m&&e[i].u==e[i+1].u&&e[i].v==e[i+1].v&&e[i].w==e[i+1].w)
            {
                i++;
                res++;
            }
            time=time*res%mod;
            cost=cost%mod;
        }
        if(cnt==n-1)break;
    }
    if(cnt==n-1)
        printf("%llu\n",cost%mod*time%mod);
    else printf("0\n");
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        kurskal();
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM