题面
原题
题目描述
众所周知,灭霸希望借助宇宙魔方的力量完成他不可告人的计划。
为了能够释放出宇宙魔方的力量,灭霸制造了一个魔方模型进行练习。
魔方模型是一个 N 层,每层 N 行 N 列的立方体。魔方的每一格会储存一定的能量,一开始每格的能量都是0。
灭霸每次可以给魔方的任意一层的 N*N 个格子同时加上 X 点能量( X 为任意整数),或者整体转动魔方(仅仅是把魔方的底面换成另一面)。若干次操作之后,魔方的一个格子意外损坏了。灭霸希望你计算出损坏的格子原本储存了多少能量。
输入格式
第一行输入一个整数 N 代表魔方的边长。
接下来有 N 块数据,第 i 块代表魔方的第 i 层。
每一块数据有 N 行,每行 N 个整数,第 x 行第 y 个整数代表这一层的第 x 行第 y 列的格子中储存了多少能量。如果某一个数是-1,代表这一格魔方损坏了。数据保证 N^3 个数中有且仅有一个 -1。
输出格式
输出一个整数代表损坏的魔方原本储存了多少能量。
样例数据
见 xoj 。
数据范围
20% 的数据1 ≤ N ≤ 5;
另外有20% 的数据,魔方的底面一直没有换过;
另外有20% 的数据,魔方的底面可能换过,但灭霸只给魔方增加过一次能量;
100% 的数据1 ≤ N ≤ 100,每格的能量数 ≤ 1000。
题意概括
一个边长为
先给出进行若干步操作后小立方体的权值,但缺失了一个(标记为
题解
Part1:乱搞做法(有漏洞,但是能AC)
思路
很显然,无论怎么操作,最后的权值之和必须是
那么有:
显然,上式中能让
那么有:
若
代码
乱搞代码如下,非常短:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int ans=1,n,f;//因为会加到一个-1,所以累加从1开始
scanf("%d",&n);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) scanf("%d",&f),ans+=f;
printf("%d",(ans/(n*n)+1)*(n*n)-ans+((ans/(n*n)+1)*(n*n)-ans==0)*(n*n));
}
漏洞
虽然代码简短,思路简洁,写出来的难度很低,并且可以拿到满分,但是它的漏洞也是很明显的。
为什么
事实上,根据上面思路,我们根本得不出
但为什么,这个错误的思路,打出来的错误的代码,可以得到
其实可以证明,在本题数据中,对于任何
部分正确性证明
由上面的推导,得:
则
而显然,
得
若
此时
hack数据
虽然对于任何 真是废话)
在此情况下,只要
输入
2
0 0
0 0
9 9
9 -1
正确输出 程序输出
9 1
但显然,出题者没有考虑到,会有一个代码在
补救
很简单,如果担心会被卡掉,只需要把
Part2:正解
我们假设第
因此只需要计算出缺失格子的颜色,然后这种颜色的总能量和其余颜色的总能量的差就是答案。
正解代码:
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int a[N][N][N],n,yu,ans1,ans2;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
scanf("%d",&a[i][j][k]);
if(a[i][j][k]==-1) yu=(i+j+k)%n,a[i][j][k]=0;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
if((i+j+k)%n==(yu==1?0:0)) ans1+=a[i][j][k];
if((i+j+k)%n==yu) ans2+=a[i][j][k];
}
}
}
printf("%d",ans1-ans2);
}
正解空间复杂度和代码长度都没有乱搞做法优呀,那谁用正解