对角线在N个方格中通过的不同矩形的数量

时间:2017-02-13 17:45:11

标签: algorithm computer-science combinatorics

我正在解决CS问题,我需要的帮助不大。我有数字N,如果矩形被分割成大小为1x1的矩形,我需要计算对角线在N个方格中经过的不同矩形的数量。这张照片将帮助您理解。

picture with rectangles

如果N = 4,这张图片显示所有4种组合,实际上对角线在4个方格中经过的矩形的大小为1x4,2x3,4x2和4x4。

如果我们给出了两个尺寸的矩形,我找到了公式:

A + B - gcd(A,B)

由于N <= 10 ^ 6,i上升到10 ^ 6并检查N的除数为N,其复杂度为O(N sqrt(N)),因为A的除数是gcd(A,B)我解决了方程组 q是A的除数,q是gcd(A,B) A + B-q = N且gcd(A,B)= q 我在O(N sqrt(N)* log(N))中解决了这个问题 其中我假设log(N)是找到两个数字的gcd的时间。

因为时间限制是3秒,所以它会按时失败。我需要有关优化解决方案的帮助。

更新:这是我的代码:

#include <bits/stdc++.h>

#define ll long long
using namespace std; 
int a;

int gcd(int a, int b) {
    if(b>a) swap(a,b);
    if(b==0) return a;
    return gcd(b, a%b);
}

bool valid(int n, int m, int gc, int a) {
    if(n+m-gc==a) return true;
    return false;
}

int main() {
cin>>a;

int counter=0;
for(int i=1;i<=a/2;i++) {
    for(ll j=1;j<=sqrt(i);j++) {
        if(i%j==0) {
            if(j!=i/j) {
                int m1 = a+j-i;
                int div=i/j;
                int m2 = a+div-i;
                if(valid(i, m1, j, a)) {
                    if(gcd(i, m1)==j)
                        counter++;
                }
                if(valid(i, m2, i/j, a)) {
                    if(gcd(i,m2)==i/j)
                        counter++;
                }

            }
            else {
                int m1 = a+j-i;
                if(valid(i, m1, j, a)) {
                    if(gcd(i, m1)==j)
                        counter++;
                }
            }
        }
    }
}
cout<<counter+1;
return 0;
}

提前致谢。

1 个答案:

答案 0 :(得分:1)

虽然O(n*sqrt(n)*log(n)) n <= 10^6听起来有点多,但您可能需要更好的算法,但您的代码支持一些优化:

int gcd(int a, int b) {
    if(b>a) swap(a,b);
    if(b==0) return a;
    return gcd(b, a%b);
}

摆脱交换,没有它就可以正常工作。

当你在这里时,也要摆脱递归:

int gcd(int a, int b) {
    while (b) {
        int r = a % b;
        a = b;
        b = r;
    }

    return a;
}

下一步:

for(int i=1;i<=a/2;i++) {
    for(ll j=1;j<=sqrt(i);j++) {

在各自的循环之外计算a/2sqrt(i)。没有必要在每次迭代时计算它。编译器可能或者可能不够智能(或设置)来做到这一点,但你不应该依赖它,特别是在在线判断设置中。

您还可以进一步预先计算i / j,以便不会每次都重新计算它。许多分歧可能很慢。

接下来,long long你真的需要j吗? i是一个int,j上升到平方根。因此long long不需要j,请使用int