【BZOJ】2321: [BeiJing2011集训]星器
Description
Magic Land上的时间又过了若干世纪……
现在,人们谈论着一个传说:从前,他们的祖先来到了一个位于东方的岛屿,那里简直就是另外一个世界。善于分析与构造的Magic Land上的人们总是不明白那里的人们是如何不借助精确的实验与计算驱动和操纵魔法。
偶然地,一个魔法使(Magician)来到了Magic Land,在临走的时候留下了一个神奇的盒子,叫做星器(Casket of star)。
虽然不知道这个盒子是做什么的,但是经过了大量的实验和计算后,人们已经清楚它的一些事实:
1.星器之中有N×M个区域,可看作分成N行和M列的格子,每个区域之中有若干单位的称为“星”的对象,这个对象的最小单位已经被确定,所以,这个数量总是整数。
2.魔法使可以驱动星器中位于同一行或同一列的不相邻(有公共边的区域称为相邻的)两个区域中各1单位的“星”,使得它们分别向中心移动1格。
3.每一次使用2中的方法驱动“星”,将会产生魔力,魔法使会得到这一部分魔力。魔力的量等于这个两个区域之间所间隔的区域数。
这样,我们可以用一个N×M的数表来表示星器的状态,比如N=2,M=3时:
2 |
0 |
1 |
1 |
2 |
0 |
||
5 |
1 |
4 |
5 |
1 |
4 |
当星器为左图的状态时,通过操纵第一行的第1和3个区域中的“星”(加粗的数字对应的区域),变为右图所示的状态,同时,将产生1单位的魔力(因为这两个区域之间恰好隔了1个区域)。
在经过了进一步的研究之后,人们知道了这个星器最初的状态(Ini)以及最终被他们得到时的状态(Fin)。
你希望知道,星器最多帮助它的拥有者提供了多少的魔力。即:经过一系列上述操作由初态(Ini)变为终态(Fin),至多产生多少魔力。
需要注意的是,显然操作过程中每个区域内“星”的数量不能是负的,即:如果那个区域已经没有“星”了,当然就不能继续操作了。
Input
第一行包含两个正整数N、M表示星器的大小。
接下来的N行,每行包含M个自然数:Iniij,描绘了初态(Ini)。
在一个空行后的N行,每行包含M个自然数:Finij,描绘了终态(Fin)。
Output
输出一个正整数,表示至多产生的魔力。
Sample Input
5 5
1 0 0 0 1
0 0 0 0 0
0 0 0 0 0
0 1 0 1 1
1 0 0 0 0
0 0 0 0 0
0 0 0 0 1
2 0 0 0 1
0 0 2 0 0
0 0 0 0 0
【输入样例2】
1 4
10 20 30 40
0 0 100 0
Sample Output
7
【样例1解释】
唯一的一种操作方法是:
对第5列的两个“星”进行一次操作,产生魔力2;
对第1列的两个“星”进行两次操作,产生魔力3+1;
对第4行的两个“星”进行一次操作,产生魔力1;
一共产生7单位的魔力。
【输出样例2】
50
HINT
【数据规模和约定】
40%的数据中N ≤ 2,如样例2;
100%的数据中1 ≤ N,M ≤ 200,Iniij,Finij ≤ 1000。
所有数据保证了至少存在一个操作方法使得星器由初态变为终态,同时保证了初态与终态不是完全相同的。
题解:
题目大意:给定两个矩阵,分别为初状态和末状态,定义一次操作为选定当前状态的矩阵的同行不同列或同列不同行的两个数,把他们的列或行“拉近”1个距离。(意会大约就是这么个意思。我也说不好QAQ)。
注意到选定的两个元素至少有一个行或者列是相同的,那么对答案的影响就是不同的部分。比如(i,j)和(i,k),(j<=k-2),那么移动之后的状态是(i,j+1)和(i,k-1)。所产生的价值就是k-j-1(根据题目定义)
现在,神奇的做法出现了……论神奇的物理方法……定义一个点的势能为这个点到原点的欧几里得距离。那么移动前后的势能改变量为(j+1)^2+(k-1)^2-j^2-k^2=2*j-2*k+2=2*(j-k+1);
于是我们发现这个△E就是我们要求的对答案的贡献值。
于是预处理之后计算即可……
魔理沙的题目啊……后面的灵梦的题我不会做QAQ……
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int MAXN = 201; int a[MAXN][MAXN], b[MAXN][MAXN]; int n, m; long long E1, E2; int main(int argc, char *argv[]) { int i, j, x; scanf("%d%d", &n, &m); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) { scanf("%d", &x); E1 += (i*i + j*j)*x; } //cout << i << ' ' << j << ' ' << n << ' ' << m << endl; for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) { scanf("%d", &x); E2 += (i*i + j*j)*x; } //cout << E1 << ' ' << E2 << endl; printf("%lld\n", (E1 - E2 >> 1)); return 0; }