bzoj2321 [BeiJing2011集训]星器 乱搞

本文介绍了一种通过计算星器状态变化产生的魔力的方法。星器由多个单元组成,每个单元含有一定数量的‘星’。通过特定的操作,可以使‘星’移动并产生魔力。文章提供了一种算法,用于计算从初始状态到最终状态所能产生的最大魔力。

Description


Magic Land上的时间又过了若干世纪……
现在,人们谈论着一个传说:从前,他们的祖先来到了一个位于东方的岛屿,那里简直就是另外一个世界。善于分析与构造的Magic Land上的人们总是不明白那里的人们是如何不借助精确的实验与计算驱动和操纵魔法。
偶然地,一个魔法使(Magician)来到了Magic Land,在临走的时候留下了一个神奇的盒子,叫做星器(Casket of star)。
虽然不知道这个盒子是做什么的,但是经过了大量的实验和计算后,人们已经清楚它的一些事实:

  1. 星器之中有N×M个区域,可看作分成N行和M列的格子,每个区域之中有若干单位的称为“星”的对象,这个对象的最小单位已经被确定,所以,这个数量总是整数。

  2. 魔法使可以驱动星器中位于同一行或同一列的不相邻(有公共边的区域称为相邻的)两个区域中各1单位的“星”,使得它们分别向中心移动1格。

  3. 每一次使用2中的方法驱动“星”,将会产生魔力,魔法使会得到这一部分魔力。魔力的量等于这个两个区域之间所间隔的区域数。

在经过了进一步的研究之后,人们知道了这个星器最初的状态(Ini)以及最终被他们得到时的状态(Fin)。
你希望知道,星器最多帮助它的拥有者提供了多少的魔力。即:经过一系列上述操作由初态(Ini)变为终态(Fin),至多产生多少魔力。

需要注意的是,显然操作过程中每个区域内“星”的数量不能是负的,即:如果那个区域已经没有“星”了,当然就不能继续操作了。

40%的数据中N ≤ 2,如样例2;
100%的数据中1 ≤ N,M ≤ 200,Iniij,Finij ≤ 1000。
所有数据保证了至少存在一个操作方法使得星器由初态变为终态,同时保证了初态与终态不是完全相同的。

Solution


神题

记一个点(i,j)的势能为i^2+j^2,那么操作前后的势能差就是答案*2
遇到这种题要咋办啊想是不可能想出来的又不会做暴力分给的又不够

Code


#include <stdio.h>
#include <string.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

typedef long long LL;
const int N=205;

int rc[N][N];

int main(void) {
    int n,m; scanf("%d%d",&n,&m);
    LL ans=0;
    rep(i,1,n) rep(j,1,m) {
        scanf("%d",&rc[i][j]);
        ans+=rc[i][j]*(i*i+j*j);
    }
    rep(i,1,n) rep(j,1,m) {
        scanf("%d",&rc[i][j]);
        ans-=rc[i][j]*(i*i+j*j);
    }
    printf("%lld\n", ans/2);
    return 0;
}
### 题目内容 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体。现在被困在了这个n维球体中,仅知道球面上n + 1个点的坐标,需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁这个球形空间产生器[^1][^2]。 ### 解题思路 - **原理依据**:根据球心的定义,球心到球面上任意一点距离都相等。设球心坐标为\((x_1,x_2,\cdots,x_n)\),球面上一点坐标为\((a_1,a_2,\cdots,a_n)\),两点距离公式为\(dist = \sqrt{(x_1 - a_1)^2+(x_2 - a_2)^2+\cdots+(x_n - a_n)^2}\)。 - **构建方程**:设球面上\(n + 1\)个点的坐标分别为\((a_{i1},a_{i2},\cdots,a_{in})\),\(i = 1,2,\cdots,n + 1\)。以第一个点和其他点为例,根据球心到各点距离相等,可得: \((x_1 - a_{11})^2+(x_2 - a_{12})^2+\cdots+(x_n - a_{1n})^2=(x_1 - a_{21})^2+(x_2 - a_{22})^2+\cdots+(x_n - a_{2n})^2\) 展开式子: \(x_1^2 - 2a_{11}x_1+a_{11}^2+x_2^2 - 2a_{12}x_2+a_{12}^2+\cdots+x_n^2 - 2a_{1n}x_n+a_{1n}^2=x_1^2 - 2a_{21}x_1+a_{21}^2+x_2^2 - 2a_{22}x_2+a_{22}^2+\cdots+x_n^2 - 2a_{2n}x_n+a_{2n}^2\) 消去\(x_1^2,x_2^2,\cdots,x_n^2\)后可得: \(2(a_{21}-a_{11})x_1 + 2(a_{22}-a_{12})x_2+\cdots+2(a_{2n}-a_{1n})x_n=a_{21}^2 - a_{11}^2+a_{22}^2 - a_{12}^2+\cdots+a_{2n}^2 - a_{1n}^2\) 同理,用第一个点和第\(i\)个点\((i = 3,\cdots,n + 1)\)可得到\(n\)个线性方程,构成一个\(n\)元一次方程组。 - **求解方程组**:使用高斯消元法求解这个\(n\)元一次方程组,得到的解就是球心的\(n\)维坐标。 ### 代码实现 ```python n = int(input()) points = [] for _ in range(n + 1): points.append(list(map(float, input().split()))) # 构建方程组的系数矩阵和常数项 a = [[0] * (n + 1) for _ in range(n)] b = [0] * n for i in range(n): for j in range(n): a[i][j] = 2 * (points[i + 1][j] - points[0][j]) b[i] += points[i + 1][j] ** 2 - points[0][j] ** 2 # 高斯消元 for i in range(n): # 选主元 max_row = i for j in range(i + 1, n): if abs(a[j][i]) > abs(a[max_row][i]): max_row = j a[i], a[max_row] = a[max_row], a[i] b[i], b[max_row] = b[max_row], b[i] # 消元 for j in range(i + 1, n): factor = a[j][i] / a[i][i] for k in range(i, n): a[j][k] -= factor * a[i][k] b[j] -= factor * b[i] # 回代求解 x = [0] * n for i in range(n - 1, -1, -1): s = 0 for j in range(i + 1, n): s += a[i][j] * x[j] x[i] = (b[i] - s) / a[i][i] # 输出结果 print(" ".join(map(lambda num: "{:.3f}".format(num), x))) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值