bzoj2321: [BeiJing2011集训]星器

题面在这里

题意:

有一个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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值