[BZOJ 2321][BeiJing2011集训]星器

物理题可还行(其实我是想学势能方法,然后误入了……

给每个星星(假设他在的位置是\((i, j)\))定义势能\(E_p = i^2 + j^2\),定义势函数\(\Phi(S)\)来表示状态\(S\)时所有星星势能的和。

然后我们发现,当两个星星互相吸引时(假设他们同行,坐标分别为\((i, j)\)和\((i, k)\),且$j<k$),他们的坐标会变为\((i, j + 1)\)和\((i, k - 1)\),势能的总减少量(也就是势函数的减小量)为\(2(k - j - 1)\)。

因此,整个过程中势函数的总减小量,就是答案的两倍。因此算出操作前后的势能做差即可……

代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <utility>
typedef long long ll;
int main() {
  int n, m; scanf("%d%d", &n, &m);
  ll E = 0LL;
  for(int i = 1; i <= n; i ++) {
    for(int j = 1; j <= m; j ++) {
      ll delta = i * i + j * j; ll x;
      scanf("%lld", &x); delta *= x;
      E += delta;
    }
  }
  for(int i = 1; i <= n; i ++) {
    for(int j = 1; j <= m; j ++) {
      ll delta = i * i + j * j; ll x;
      scanf("%lld", &x); delta *= x;
      E -= delta;
    }
  }
  E /= 2LL;
  printf("%lld\n", E);
  return 0;
}