当给定网格大小N x M时,我必须解决一个问题,我必须找到“可以放入其中”的平行四边形的数量,这样它们每个坐标都是一个整数。
这是我的代码:
/*
~Keep It Simple!~
*/
#include<fstream>
#define MaxN 2005
int N,M;
long long Paras[MaxN][MaxN]; // Number of parallelograms of Height i and Width j
long long Rects; // Final Number of Parallelograms
int cmmdc(int a,int b)
{
while(b)
{
int aux = b;
b = a -(( a/b ) * b);
a = aux;
}
return a;
}
int main()
{
freopen("paralelograme.in","r",stdin);
freopen("paralelograme.out","w",stdout);
scanf("%d%d",&N,&M);
for(int i=2; i<=N+1; i++)
for(int j=2; j<=M+1; j++)
{
if(!Paras[i][j])
Paras[i][j] = Paras[j][i] = 1LL*(i-2)*(j-2) + i*j - cmmdc(i-1,j-1) -2; // number of parallelograms with all edges on the grid + number of parallelograms with only 2 edges on the grid.
Rects += 1LL*(M-j+2)*(N-i+2) * Paras[j][i]; // each parallelogram can be moved in (M-j+2)(N-i+2) places.
}
printf("%lld", Rects);
}
示例:对于2x2网格,我们有22个可能的平行四边形。
我的算法工作正常,但我需要让它快一点。我想知道怎么可能。
P.S。我听说我应该预先处理最大公约数并将其保存在一个数组中,这会将运行时间减少到O(n * m),但我不知道如何在不使用cmmdc的情况下执行此操作(最大公约数)。
答案 0 :(得分:0)
确保N不小于M:
if( N < M ){ swap( N, M ); }
利用循环中的对称性,您只需要将j从2运行到i:
for(int j=2; j<=min( i, M+1); j++)
你不需要额外的数组Paras
,放弃它。而是使用临时变量。
long long temparas = 1LL*(i-2)*(j-2) + i*j - cmmdc(i-1,j-1) -2;
long long t1 = temparas * (M-j+2)*(N-i+2);
Rects += t1;
// check if the inverse case i <-> j must be considered
if( i != j && i <= M+1 ) // j <= N+1 is always true because of j <= i <= N+1
Rects += t1;
使用余数运算符替换此行:b = a -(( a/b ) * b);
:
b = a % b;
缓存cmmdc结果可能是可能的,你可以使用筛选算法初始化数组:创建一个由a和b索引的二维数组,在每个位置放置“2”,其中a和b是2的倍数,然后在每个位置放一个“3”,其中a和b是3的倍数,依此类推,大致如下:
int gcd_cache[N][N];
void init_cache(){
for (int u = 1; u < N; ++u){
for (int i = u; i < N; i+=u ) for (int k = u; k < N ; k+=u ){
gcd_cache[i][k] = u;
}
}
}
不确定它是否有帮助。
答案 1 :(得分:0)
代码中的第一条评论说“保持简单”,因此,鉴于此,为什么不尝试以数学方式解决问题并打印结果。
如果您从网格中选择两条长度为N的线,您将通过以下方式找到平行四边形的数量:
(N-1)^2
这样做的方法,因为你可以将这两点放在N-1
上
每条线上的位置。(N-2)^2
种方法。N-2
个空格。(N-1)^2+(N-2)^2+(N-3)^2+...+1
。1/6*N*(2*N^2-3*N+1)
。点击WolframAlpha进行验证。既然你有两条线的解决方案,你只需要将它乘以M的2阶combinations的数量,即M!/(2*(M-2)!)
。
因此,整个公式为:1/12*N*(2*N^2-3*N+1)*M!/(M-2)!
,其中!
标记表示factorial,^
表示幂运算符(请注意,相同的符号是不是C ++中的幂运算符,而是按位XOR
运算符。)
此计算需要较少的迭代遍历矩阵的操作。