用于查找具有奇数no除数的数字的程序

时间:2017-04-01 15:39:44

标签: c optimization

给定2个整数L和R,你应该找到L和R之间具有奇数除数的整数。

输入格式:

第一行包含单个整数T. ,测试用例的数量。每个下一个T行包含两个空格分隔的整数Li和Ri,描述了第i个测试用例的参数。

约束

1≤T≤10000

1≤L≤R≤10^ 18

#include <stdio.h>

int main(void)
{
    int t;
    long int cnt,countj;
    scanf("%d",&t);
    long long int l[t], r[t];
    int i=0;
    for(i=0;i<t;i++){
        scanf("%d%d",&l[i],&r[i]);
        }

    int div[t];
    for(i=0;i<t;i++){
        //count[i]=0;
        cnt=0;
        for(int j=l[i]+1;j<r[i];j++){
            countj=0;
            for(int k=1;k<=j/2;k++){
                if(j%k==0)
                   countj++;
            }
            if ((countj%2)==0)
            cnt++;
        }
        printf("%ld\n",cnt);
    }
    return 0;
}

这个程序执行时间太长,特别是对于更大的数字,它如何优化? 并且它会传递所有测试用例,代码中可能出现错误吗?

2 个答案:

答案 0 :(得分:0)

你是说你要计算具有奇数除数的数字,但是你在计数偶数的数。

答案 1 :(得分:0)

如果问题确实如你所描述的那样,有一些许多方法可以提高性能,其中只有一个在下面,但你必须理解你想要完成的理论背后的理论第一。

具有奇数除数的整数总是完美正方形。给定一些数字N,如果X是除数,则必须有一些对应的Y,以使XY=N成立。他们总是成对出现。例外是完美正方形。在这种情况下,他们的数字有一些除数WWW=NW只计算为一个除数。因此N有一个奇数个除数。

那么这有什么用呢?好吧,你声明的任务是查找从LR的所有整数,这些整数具有奇数的除数。但我们只是表明只有完美的方块才有这样的属性。因此,这个问题的真正含义是:

  

找出两个整数LR之间的完美平方数。

一个这样的算法就是这样:

  • L开始,取考试号的浮点平方根
  • 转换为适当的整数类型
  • 后将根平方
  • 如果根的平方结果是原始数字,则您有一个完美的正方形。停止循环。
  • 否则,请增加测试编号,然后重试。如果您通过R或找到一个完美的正方形,无论哪个首先,请停止。

如果你没有找到完美的方块,那么答案是零,你已经完成了。如果您找到了完美的正方形,则不再需要在LR之间逐步循环。你有一个起点(一个完美的根),现在你将通过逐步增加该根来循环,直到它的方超过 R。这将显着减少迭代次数。

在下面的代码中:

  • T:测试次数
  • L:测试系列中的第一个数字
  • R:测试系列中的最后一个数字
  • NLR 之间的奇数除数值
  • sr:我们发现的正方形运行循环。

<强>代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
    unsigned int T = 0;
    if (scanf("%u", &T) != 1)
        return EXIT_FAILURE;

    while (T--)
    {
        unsigned int L, R, N=0, sr, i;
        if (scanf("%u %u", &L, &R) != 2)
            return EXIT_FAILURE;

        for (i=L; i<=R; ++i)
        {
            sr = sqrt(i);
            if (sr * sr == i)
                break;
        }

        if (i <= R)
            for (;sr*sr <= R; ++sr,++N);

        printf("%u\n", N);
    }

    return 0;
}

<强>输入

5 
1 2 
10 100
100 1000
500 2500
1 262144

<强>输出

1
7
22
28
512

<强>性能

此代码表现良好],考虑到它有多少。使用clang 3.9.1与-x c -O2进行的反汇编是可敬的。

.LC0:
        .string "%u"
.LC1:
        .string "%u %u"
.LC3:
        .string "%u\n"
main:
        push    rbp
        push    rbx
        xor     eax, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     ebp, 1
        sub     rsp, 40
        lea     rsi, [rsp+20]
        mov     DWORD PTR [rsp+20], 0
        call    __isoc99_scanf
        cmp     eax, 1
        je      .L24
.L1:
        add     rsp, 40
        mov     eax, ebp
        pop     rbx
        pop     rbp
        ret
.L24:
        mov     ebp, eax
        mov     eax, DWORD PTR [rsp+20]
        lea     edx, [rax-1]
        test    eax, eax
        mov     DWORD PTR [rsp+20], edx
        je      .L25
.L3:
        lea     rdx, [rsp+28]
        lea     rsi, [rsp+24]
        xor     eax, eax
        mov     edi, OFFSET FLAT:.LC1
        call    __isoc99_scanf
        cmp     eax, 2
        jne     .L1
        mov     ebx, DWORD PTR [rsp+24]
        cmp     ebx, DWORD PTR [rsp+28]
        jbe     .L10
        jmp     .L11
.L26:
        add     ebx, 1
        cmp     DWORD PTR [rsp+28], ebx
        jb      .L11
.L10:
        pxor    xmm0, xmm0
        mov     eax, ebx
        pxor    xmm2, xmm2
        cvtsi2sdq       xmm0, rax
        ucomisd xmm2, xmm0
        sqrtsd  xmm1, xmm0
        jbe     .L8
        movsd   QWORD PTR [rsp+8], xmm1
        call    sqrt
        movsd   xmm1, QWORD PTR [rsp+8]
.L8:
        cvttsd2si       rax, xmm1
        mov     edx, eax
        mov     ecx, eax
        imul    edx, eax
        cmp     edx, ebx
        jne     .L26
        mov     edi, DWORD PTR [rsp+28]
        cmp     ebx, edi
        ja      .L11
.L12:
        add     eax, 1
        mov     edx, eax
        mov     esi, eax
        imul    edx, eax
        sub     esi, ecx
        cmp     edi, edx
        jnb     .L12
        mov     edi, OFFSET FLAT:.LC3
        xor     eax, eax
        call    printf
.L27:
        mov     eax, DWORD PTR [rsp+20]
        lea     edx, [rax-1]
        test    eax, eax
        mov     DWORD PTR [rsp+20], edx
        jne     .L3
.L25:
        xor     ebp, ebp
        jmp     .L1
.L11:
        xor     esi, esi
        mov     edi, OFFSET FLAT:.LC3
        xor     eax, eax
        call    printf
        jmp     .L27

就是这样。它可以做得更快,但只要它满足你的性能需求,它可能不值得更多的努力(所以我希望它这样做)通常关于奇数除数的问题也要求最低(或最高)的一个数字除数的数量,这使得它更加复杂。你提出的问题没有提出这个问题,因此问题很好地减少了。