其他分享
首页 > 其他分享> > 2021牛客多校第三场 B - Black and white(kruskal+桶排序)

2021牛客多校第三场 B - Black and white(kruskal+桶排序)

作者:互联网

可以发现将整张图涂完需要n+m-1次,而每涂完一个点,这个点便可以影响到此点所在的一整列和一整行,我们考虑每填涂完一个点后将这些行和列放入一个连通块,则容易得出:当所有行和列连通时,填涂完毕。

行和列的总和一共有n+m,填涂需要n+m-1次,需要用到连通块,这三点结合起来容易让人想到Kruskal算法求最小生成树

 

需要注意的时,kruskal需要排序,而当极限数据时,点数总数n*m=25000000,此时快速排序是一定会超时的,考虑使用其他排序方法,观察数据范围发现p的大小不超过100000,于是考虑使用桶排序,则此时的时间复杂度可以接受

 

 

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
#define ll long long
int fa[2000020];
ll ans;
int a,b,c,d,p;
int n,m;
struct U{
    int x;
    int y;
    ll z;
    U(int x_,int y_,ll z_):x(x_),y(y_),z(z_){}
};
 
 vector<U>E[1000010];
 
int find(int x)
{
    if(fa[x]==x)return x;
    else return fa[x]=find(fa[x]);
}
void unio(int x,int y)
{
    fa[find(x)]=find(y);
}
int cnt=1;
void work()
{
    cnt=n+m-1;
    //int now=min(n*m,2000000);
    int now=n*m;
    for(int k=0;k<=p;k++)
    {
        for(int i=0;i<E[k].size();i++)
        {
        if(!cnt)break;
        if(find(E[k][i].x)==find(E[k][i].y+n))continue;
        unio(E[k][i].x,E[k][i].y+n);
        cnt--;
        ans+=E[k][i].z;
        }
    }
    cout<<ans;
}

int cmp(U a,U b)
{
    return a.z<b.z;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n+m;i++)fa[i]=i;
    scanf("%d%d%d%d%d",&a,&b,&c,&d,&p);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
        int t;
        int A;
        ans++;
        A=a;
        t=((ll)A*A*b+(ll)A*c+d)%p;
        a=t;
        E[t].push_back(U(i,j,t));
        }
    }
    ans=0;
    work();
    return 0;
}

 

标签:ll,int,kruskal,多校,fa,排序,include,find,第三场
来源: https://www.cnblogs.com/lemonGJacky/p/15303874.html