题意:给你一个n*m的的白色棋盘,染黑一个格子需要c[i,j]的代价,当2*2的正方形有三个被染黑时,剩下一个可以免费染黑,求染黑棋盘的最小代价。
分析:发现至少需要n+m-1个格子染黑(横一下竖一下)。考虑把格子的坐标转化为 二分图的边的两顶点,就是要通过选择n+m-1条边把两边一共n+m个点连接起来,即kruskal最小生成树。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int fa[10005];
vector<int>mp[100005];
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
signed main()
{
int n,m,a,b,c,d,p;
cin>>n>>m>>a>>b>>c>>d>>p;
int aa=a;
for(int i=0;i<n*m;i++)
{
aa=(aa*aa*b+aa*c+d)%p;
mp[aa].push_back(i);//格子的值对应第几个格子
}
for(int i=0;i<n+m;i++) fa[i]=i;
int ans=0,cnt=0;
for(int i=0;i<p;i++)
{
for(int j=0;j<mp[i].size();j++)
{
int x=mp[i][j]/m,y=mp[i][j]%m;
if(find(x)!=find(y+n))
{
cnt++;
ans+=i;
fa[find(x)]=find(y+n);
}
if(cnt==n+m-1)
{
cout<<ans<<endl;
return 0;
}
}
}
}