//编译器级优化
// #pragma GCC optimize("O2")
#include <bits/stdc++.h>
// #include <string>
// #include <iostream>
// #include <vector>
// #include <queue>
// #include <stack>
// #include <map>
// #include <time.h>
// #include <cstring>
// #include <cmath>
// #include <set>
// #include <unordered_map>
// #include <algorithm>
// #include <cstdio>
// #include <cassert>
// #include <bitset>
// #include <bits/extc++.h>
//外部包含文件
// #include "D:/program_learning/vs_code/workplace/ACMtemplate/data_structure/SparseTable.hpp"
// #include "D:/program_learning/vs_code/workplace/ACMtemplate/computational_geometry/Convex.hpp"
//类型别名
using namespace std;
// using B_ll = __int128_t;
// using B_ull = __uint128_t;
using f32 = float;
using f64 = double;
using ll = long long;
//排序用
#define htl(v, n) (v),(v)+(n), greater<decltype((v)[1])>()
#define lth(v, n) (v),(v)+(n), less<decltype((v)[1])>()
//宏函数
#define Mt(args...) make_tuple(args)
#define Mp(a, b) make_pair((a), (b))
#define Gt(a, b) std::get<(b)>((a))
#define Add(a, b) accumulate((a), (b), 0)
#define Abs(a) (((a) > 0) ? (a) : -(a))
#define Max(a, b) (((a) > (b)) ? (a) : (b))
#define Min(a, b) (((a) < (b)) ? (a) : (b))
#define Ceil(a, b) (((a) + (b) - 1) / (b))
#define Floor(a, b) ((a) / (b))
#define Pow2(x) ((x) * (x))
#define Pow3(x) ((x) * (x) * (x))
//浮点数关系运算
#define isZero(x) ((x)>0?(x):-(x)<eps)
#define equal(x, y) (abs((x)-(y))<eps)
#define lthan(x, y) ((y)-(x)>eps)
#define bthan(x, y) ((x)-(y)>eps)
//简化循环
#define FOR(i, a, b) for(int i = (ll)(a); i <= (ll)(b); i++)
#define rFOR(i, a, b) for(int i = (ll)(a); i >= (ll)(b); i--)
#define gFOR(i, a) for(int i = h[(a)] ; ~i ; i = ne[i])
#define bFOR(i, a, b) for(int i = (a); i <= (b); i <<= 1)
#define jFOR(i, a, b, step) for(int i = (a); i <= (b); i += (step))
#define iFOR(it, begin, end) for(auto it = (begin); it!=(end);it++)
#define aFOR(a, s) for(auto (a) : (s))
//debug用
#define _var(x) cout << #x << " = " << (x) << endl
#define _arr1(a, n) for(ll j = 0 ; j < (n) ; j ++) cout << (a)[j] << ((j == (n) - 1) ? endl : space)
#define _arr2(a, n, m) for(ll i = 0; i < (n); i ++) _arr1((a)[i] + 1, (m))
#define checktime() cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n" ; system("pause")
//加快io
#define endl "\n"
#define __faster_io__ std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0);
//操作输出
#define space " "
#define setd(n) fixed << setprecision(n)
//初始化设置
#define case(t,i) ll t;cin >> t;for(ll i=1;i<=t;i++)
#define _set(b, c) memset((b), (c), sizeof(b))
//模板函数
template<typename T>
int read(T& result) { // fast read
char ch;int w = 1;
result = 0;
ch = getchar();
while(ch != '-' && !(ch >= '0' && ch <= '9'))
ch = getchar();
if(ch == '-')
w = -1;
while(isdigit(ch)){
result = result * 10 + (ch - '0');
ch = getchar();
}
result *= w;
return 1;
}
template<typename T>
void write (T x) { // fast output
string tmp;string tail = (x < 0) ? "-" : "";
while(x){
tmp += x % 10 + '0';
x /= 10;
}
tmp += tail;
reverse(tmp.begin(), tmp.end());
cout << tmp;
}
template<typename T>
T qpow(T x, T n, const T& mod){
ll ans = 1;
while(n){
if(n & 1)
ans = ans % mod * x % mod;
x = x % mod * x % mod;
n >>= 1;
}
return ans;
}
template<typename T>
inline T lowbit(T& x){
return x&-x;
}
template<typename T>
T m_plus(T a, T b, const T& mod){
return (a % mod + b % mod) % mod;
}
template<typename T>
T m_minus(T a, T b, const T& mod){
return ((a % mod - b % mod) % mod + mod) % mod;
}
template<typename T>
T m_mult(T a, T b, const T& mod){
return a % mod * b % mod;
}
template<typename T>
T Mod(T x, T y)
{
return (x % y + y) % y;
}
//常数
constexpr f32 fINF32 = 1e30;
constexpr f64 fINF64 = 1e300;
constexpr int INF32 = 0x3f3f3f3f;
constexpr ll INF64 = 0x3f3f3f3f3f3f3f3f;
constexpr f32 _fINF32 = -1e30;
constexpr f64 _fINF64 = -1e300;
constexpr int _INF32 = 0xcfcfcfcf;
constexpr ll _INF64 = 0xcfcfcfcfcfcfcfcf;
constexpr f64 eps = 1e-9;
const f64 pi = acos(-1);
constexpr ll mod = 9 + 7;
constexpr ll Bit = 1 << 20;
constexpr ll N = 5e3 + 5;
/*定义全局变量*/
int g[2 * N][2 * N]; // 单个边的边权不会超int
int dist[2 * N]; // 某个点到最小生成树的最短距离也不会超过int
bool vis[2 * N];
ll n, m, a, b, c, d, p; // n * m有可能爆int,所以要用long long存
/*辅助函数*/
ll prim(){ // 注意边权和可能比较大,所以应该返回ll
_set(dist, 0x3f); // 初始化所有点距最小生成树上的点的最小距离为正无穷,表示还没有一个点在最小生成树上。
ll ans = 0; // 返回的权值和
dist[1] = 0; // 从1号点开始生成最小生成树
FOR(_, 1, n + m){ // 因为最外层循环的循环变量不需要使用,所以命名为_,防止重名。
ll mn = 0; // 初始化距最小生成树距离最小的点为0号点,0号点实际上不存在在图中,主要作为哨兵使用,可以简化边界条件。
FOR(j, 1, n + m){
if(!vis[j] && dist[j] < dist[mn]){ // 找到距最小生成树距离最小的点
mn = j;
}
}
vis[mn] = true; // 当前找到的这个点一定在最小生成树上,将它归入已经在树上的点的集合
ans += dist[mn]; // 在最终答案里加上当前找到的点的距离
FOR(j, 1, n + m){
if(!vis[j] && g[j][mn] < dist[j]){ // 因为有新点加入最小生成树,所以用该点更新一下其他点距最小生成树的距离
dist[j] = g[j][mn];
}
}
}
return ans;
}
void solve(){
// 根据题意,g[i][j]表示生成的矩阵中i行j列的数值,可以将原题转化成,g[i][j]表示从a[i]点到b[j]点连的一条无向边的权值,将g[i][j]染黑,即表示
// 选择a[i]到b[j]这条边,并将a[i]和b[j]这两点归入一个已经联通的点的集合中,代价是边权;
// 再考虑另一个条件,任选两行i, j和两列m, n,考虑当g[i][m], g[i][n], g[j][m]已经被染黑时g[j][n]自动被染黑,
// 即当已经存在a[i]到b[m],a[i]到b[n],a[j]到b[m]的边时,也即a[i],a[j],b[n],b[m]已经联通时,就可以不用再考虑a[j]到b[n]的边了,
// 于是问题转化成了,在这些边中选择一些边,使得所有点联通,并且选择的边权和最小,于是便可以用原矩阵建图跑最小生成树算法即可,
// 注意这里如果使用克鲁斯卡尔算法的话,直接对边权排序会超时,所以选择prim算法,时间复杂度O(n^2)可以满足要求。
_set(g, 0x3f); // 注意模p下边权有可能为0,所以要用正无穷来表示两个点不连通。
cin >> n >> m >> a >> b >> c >> d >> p;
FOR(i, 0, n * m - 1){ // 按照题意生成原矩阵
int x = i / m + 1, y = i % m + 1;
a = (Pow2(a) * b + a * c + d) % p;
g[x + m][y] = g[y][x + m] = a; // 邻接矩阵建图,大小为(n+m) * (n+m)
}
// _arr2(g + 1, n + m, n + m);
cout << prim() << endl;
}
/*程序入口*/
int main()
{
#ifdef LOCAL
freopen("D:/program_learning/vs_code/workplace/ACMtemplate/DataIn.txt", "r", stdin);
freopen("D:/program_learning/vs_code/workplace/ACMtemplate/DataOut.txt", "w", stdout);
#endif
__faster_io__
// case(t, i){
solve();
// }
#ifdef LOCAL
cout.flush();
freopen("CON", "r", stdin);
freopen("CON", "w", stdout);
#endif
checktime();
return 0;
}
2021牛客暑假多校训练#3 B.Black and white
最新推荐文章于 2024-07-15 11:08:21 发布