Black and white 题解(思维+prim)

题目链接

题目大意

给你一个\(n\times m\)的矩阵,每个矩阵有权值\(cost[i][j]\)

若任意两行两列的相交的四个点,有三个点使用了权值,则第四个点则不需要权值

求最后最少花费多少权值

题目思路

若三个点使用了权值,则第四个点不需要使用权值,那么你会现在这四个点的联通性没有改变

所以可以把每一行每一列看作一点

相当于\(n+m\)个点 \(n\times m\)条边的图,要你求最小生成树

\(prim\)算法复杂度是\(O(点数^2)\)

\(Kruskal\)算法复杂度为\(0(边\times log(边))\)

对于稠密图使用\(prim\),稀疏图使用\(Kruskal\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//typedef pair<int,int> pii;
#define fi first
#define se second
#define debug printf("aaaaaaaaaaa\n");
const int maxn=5e5+5,inf=0x3f3f3f3f,mod=998244353;
const ll INF=0x3f3f3f3f3f3f3f3f;
ll n,m,a,b,c,d,p;
ll cost[5000+5][5000+5];
bool vis[2*maxn];
ll dis[maxn];
ll ans;
void prim(){
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;
    for(int _=1;_<=n+m;_++){
        int u=-1;
        for(int i=1;i<=n+m;i++){
            if(!vis[i]&&(u==-1||dis[i]<dis[u])){
                u=i;
            }
        }
        ans+=dis[u];
        vis[u]=1;
        if(u>n){
            for(int i=1;i<=n;i++){
                if(!vis[i]&&dis[i]>cost[i][u-n]){
                    dis[i]=cost[i][u-n];
                }
            }
        }else{
            for(int j=1;j<=m;j++){
                if(!vis[j+n]&&cost[u][j]<dis[j+n]){
                    dis[j+n]=cost[u][j];
                }
            }
        }
    }
}
int main(){
    cin>>n>>m>>a>>b>>c>>d>>p;
    ll temp=a;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            temp=(temp*temp*b+temp*c+d)%p;
            cost[i][j]=temp;
        }
    }
    prim();
    cout<<ans<<'\n';
    return 0;
}

不摆烂了,写题
原文地址:https://www.cnblogs.com/hunxuewangzi/p/15059910.html