您的位置:首页 > 其它

bzoj2321: [BeiJing2011集训]星器

2018-01-17 14:30 351 查看
题面在这里

题意:

有一个n*m的方格,每一格有a[i,j]个星。

现在每次可以取同一行或同一列的两颗星,让他们向中心移动一格,并且获得他们中间隔的区域数个能量。

给定最终状态,问最多可能获得的能量。

做法:

首先“最多”这个东西是来忽悠你的。

发现获得的能量是一定的。行列独立。

然后我们来推一波式子。

假设有一行是这样的:

1 0 0 0 0 … 0 0 1

最左边的左边为(x,y),最右边的坐标为(x,y+n-1)。中间相隔n-2个区域。

移动一格后,变成:

0 1 0 0 0 … 0 1 0

新的两个格子变成(x,y+1),(x,y+n-2)。

(x^2+y^2+x^2+(y+n-1)^2)-(x^+(y+1)^2+x^2+(y+n-2)^2)这个式子展开化简得到

=2n-4=2(n-2)

把它除以2就是获得的能量。

于是我们得到了结论:

所有格子的星星数量乘行列的平方和,初始和最终状态相减就是答案。

然后这个东西究竟为什么是这样很玄学,黄学长博客上是这么写的,大概涉及到了物理知识qaq:

一个星星的势能定义为他到左上角格子的距离的平方(即,行号的平方和列号的平方的和),可知,使用一次魔法释放出的魔力就是两个星星的势能和的改变量/2。这样,计算初、末状态的所有星星的势能和,相减/2即可。”

(怎么感觉跟没说差不多)

易错点:

注意开long long。

代码:

/*************************************************************
Problem: bzoj 2321 [BeiJing2011集训]星器
User: fengyuan
Language: C++
Result: Accepted
Time: 52 ms
Memory: 1288 kb
Submit_Time: 2018-01-17 14:07:35
*************************************************************/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long ll;

int n, m;
ll ans, x;

int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) {
scanf("%lld", &x);
ans += x*(i*i+j*j);
}
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++) {
scanf("%lld", &x);
ans -= x*(i*i+j*j);
}
printf("%lld\n", ans/2);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: