标签:namespace str div i+1 ros bool content algo 过程
题目描述
输入
输出
样例输入
3 2 2
1
1
1
1 2
1 1
样例输出
65
题解
并查集
首先容易发现,所有方格的连接是一个类似于最小生成树的过程。
因此我们先把每个隔板按照高度从小到大排序,然后一个一个加入。
对于每一个连通块,维护其:连通的最小高度(即最后加的一条边)$last[i]$ 、和连通之前的方案数 $v[i]$ 。
那么高度为 $z$ 时合并两个连通块 $x$ 和 $y$ ,形成新连通块的 $last$ 等于 $z$,方案数等于 $(v[x]+z-last[x])(v[y]+z-last[y])$ 。
如果最终的连通块为 $i$ ,则最后的答案即为 $v[i]+H-last[i]$ 。
时间复杂度 $O(nm\log n)$
#include <cstdio>
#include <algorithm>
#define N 500010
#define mod 1000000007
#define pos(i , j) ((i - 1) * m + j)
using namespace std;
typedef long long ll;
struct data
{
int x , y , z;
data() {}
data(int a , int b , int c) {x = a , y = b , z = c;}
bool operator<(const data &a)const {return z < a.z;}
}a[N << 1];
int f[N] , last[N] , tot;
ll v[N];
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
int main()
{
int n , m , k , i , j , x , y;
scanf("%d%d%d" , &n , &m , &k);
for(i = 1 ; i <= n ; i ++ )
for(j = 1 ; j < m ; j ++ )
scanf("%d" , &x) , a[++tot] = data(pos(i , j) , pos(i , j + 1) , x);
for(i = 1 ; i < n ; i ++ )
for(j = 1 ; j <= m ; j ++ )
scanf("%d" , &x) , a[++tot] = data(pos(i , j) , pos(i + 1 , j) , x);
sort(a + 1 , a + tot + 1);
for(i = 1 ; i <= n * m ; i ++ ) f[i] = i , last[i] = -1;
for(i = 1 ; i <= tot ; i ++ )
{
x = find(a[i].x) , y = find(a[i].y);
if(find(x) != find(y)) v[y] = (v[y] + a[i].z - last[y]) * (v[x] + a[i].z - last[x]) % mod , last[y] = a[i].z , f[x] = y;
}
x = find(1);
printf("%lld\n" , (v[x] + k - last[x]) % mod);
return 0;
}
标签:namespace str div i+1 ros bool content algo 过程
原文地址:http://www.cnblogs.com/GXZlegend/p/8007116.html