题目链接
题目大意
给你一个\(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;
}