给定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;
}
这个程序执行时间太长,特别是对于更大的数字,它如何优化? 并且它会传递所有测试用例,代码中可能出现错误吗?
答案 0 :(得分:0)
你是说你要计算具有奇数除数的数字,但是你在计数偶数的数。
答案 1 :(得分:0)
如果问题确实如你所描述的那样,有一些许多方法可以提高性能,其中只有一个在下面,但你必须理解你想要完成的理论背后的理论第一。
具有奇数除数的整数总是完美正方形。给定一些数字N
,如果X
是除数,则必须有一些对应的Y
,以使XY=N
成立。他们总是成对出现。例外是完美正方形。在这种情况下,他们的数字有一些除数W
,WW=N
和W
只计算为一个除数。因此N
有一个奇数个除数。
那么这有什么用呢?好吧,你声明的任务是查找从L
到R
的所有整数,这些整数具有奇数的除数。但我们只是表明只有完美的方块才有这样的属性。因此,这个问题的真正含义是:
找出两个整数
L
和R
之间的完美平方数。
一个这样的算法就是这样:
L
开始,取考试号的浮点平方根R
或找到一个完美的正方形,无论哪个首先,请停止。如果你没有找到完美的方块,那么答案是零,你已经完成了。如果您找到了完美的正方形,则不再需要在L
和R
之间逐步循环。你有一个起点(一个完美的根),现在你将通过逐步增加该根来循环,直到它的方超过 R
。这将显着减少迭代次数。
在下面的代码中:
T
:测试次数L
:测试系列中的第一个数字R
:测试系列中的最后一个数字N
:L
和R
之间的奇数除数值 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
就是这样。它可以做得更快,但只要它满足你的性能需求,它可能不值得更多的努力(所以我希望它这样做)通常关于奇数除数的问题也要求最低(或最高)的一个数字除数的数量,这使得它更加复杂。你提出的问题没有提出这个问题,因此问题很好地减少了。