-3

给定一个以 1、3、7 或 9 结尾的数字 N。

总会存在一个数字 M,当它以相同的原始数字 N 结束时,M 永远不需要比 N 多的数字。

示例:- N=123。M=947。(947)^3=849278123。这里 (947)^3 以 N(即 123) 结尾。

编写一个程序,以 N 作为输入并找到 M,其中 M 是与 N 最多相同的位数,当立方数以 N 结尾时。

我将代码编写为:

#include "iostream"
#include "math.h"
using namespace std;

int main()
{
    long long int t,p,j,i,d,c,s;
    cin>>t;
    long long int *n= new long long int[t];
    for(i=0;i<t;i++)
    {
        cin>>n[i];
    }
    for(i=0;i<t;i++)
    {   d=0; j=1;
        p=n[i];
        while(p)
        {
            d++;
            p=p/10;

        } p=n[i];
        s= pow(10,d);
        while(1)
        {
            c=j*j*j;
            if(c%s==p){break;}
            j++;

        }
    cout<<j<<endl;
     }
    return 0;
}

时间限制为 1 秒。时间限制超过1。

4

3 回答 3

4

你可以做很多事情。首先 - 请注意以奇数结尾的立方体必须以奇数开始 - 所以只尝试 M 的奇数。节省时间的因子 2。

下一步 - 要查找数字的最后 3 位数字,只需执行number % 1000. 并且不要使用pow. 它非常慢。请参阅我的技巧来找到数字的大小。

你最终会得到这样的结果:

long int N, M, div;

printf("what is the value of N?\n");
scanf("%d", &N);
// test that it is reasonable before continuing...
// I did not write that code, but you should (size of N, and does it end in 1, 3, 7, or 9?

// find out how many digits N has:
div = 1;
while(N / div > 0) {
  div *= 10;
}

// now loop around odd M
for(M = 1; M < div; M+=2) {
  if( (M*M*M)%d==N) break;
}
// when you come out of this loop, M is the number you were looking for.

最后一个调整 - 看看数字的立方体。

1*1*1 = 1
3*3*3 = 27

7*7*7 = 343
9*9*9 = 729

由此您得出结论,如果N以 结尾1,您可以只检查以 结尾的数字1

for(M=1; M<div; M+=10) {

其他值类似(3 - 从 M=7 开始;7 - 从 M=3 开始;9 - 从 M=9 开始)。现在我们的代码速度提高了 10 倍......

可能不足以赢得比赛,但它应该有助于......

EDIT刚刚运行了以下代码,它在 0.02 秒内给出了与上面相同的答案(在算法运行 10,000 次之后) - 大约需要 20 微秒才能找到 M 一次......注意 - 更新的m1数组,所以代码应该可以工作对于以“有效”数字结尾的数字5(尽管不能保证数字会存在 - 并且问题明确询问了以 1、3、7 和 9 结尾的数字)。

#include <stdio.h>
#include <time.h>

int main(void) {
    long long int N, M, div;
    long long int m1[] = {0, 1, 0, 7, 0, 5, 0, 3, 0, 9};
    time_t start, end;
    int ii;
    printf("what is the value of N?\n");
    scanf("%lld", &N);
    // test that it is reasonable before continuing...
    // I will leave that for you to do

    start = clock();
    // now starts the main loop
    // I go around it 10,000 times to get a "reasonable accuracy" since the clock()
    // function is not very granular (it was giving me "elapsed time zero")
    // obviously for competition you want to do this just once!
    for (ii = 0; ii < 10000; ii++) {
      // find out how many digits N has:
      div = 1;
      while(N / div > 0) {
        div *= 10;
      }

      // now try possible values of M - given the last digit of N
      // we know what the last digit of M should be
      // so we can start with that number, then take steps of 10
      for(M = m1[N % 10]; M < div; M+=10) {
        if( ( M * M * M ) % div == N ) break;
      }

    } // do it 10,000 times to get some time on the clock

   // when you come out of this loop, M is the number you were looking for.
   // since the loop stops at div, it should never be larger than N
    printf("M is now %lld\n", M);

    printf("M cubed is %lld which ends in %lld\n", M * M * M, ( M * M * M ) % div);

    end = clock();

    printf("Time taken: %f sec\n", ((float)(end - start) ) / CLOCKS_PER_SEC);
}
于 2013-10-19T18:49:08.973 回答
1

蛮力方法——遍历所有可能性。应用数学可能会绕着这个转圈,但现在我让应用逻辑来统治。0.021337 秒找到答案10000 次;运行一次需要 0.000004 秒,这是相当大的舍入。

作为奖励,它似乎也适用于以“5”结尾的值。

(编辑)Applied Logic 建议您不必检查 M > 1000。毕竟,(1000+M)³ = 1000³ + 3*M²*1000 + 3*M*1000² + M³,因为我们正在使用mod所有东西1000 以上被取消,计算减少到 M³ - 我想知道,也许我们应该将此问题移至 math.stackexchange.com。

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

int main(int argc, char **argv)
{
    long long int N, M, val;
    int ii;
    time_t start, end;

    if (argc == 2)
        N = strtoul (argv[1], NULL, 10);
    else
    {
        printf("what is the value of N?\n");
        scanf("%lld", &N);
    }

    if (~N & 1)
    {
        printf ("invalid input\n");
        return EINVAL;
    }

    start = clock();
    for (ii=0; ii<10000; ii++)
    {
    for (M=1; M<1000; M+=2)
    {
        val = M%1000;
        val = val*val*val;
        if ((val % 1000) == N)
            break;
    }
    }
    end = clock();

    printf("For N=%lld, M=%lld, cubed is %lld which ends in %lld\n", N, M, M*M*M, (M*M*M)%1000);

    printf("Time taken: %f sec for 10,000 loops\n", ((float)(end - start) ) / CLOCKS_PER_SEC);

    return 0;
}
于 2013-10-19T20:45:30.403 回答
0

让我们取数字 N 并重复计算它的三次方(模 1000):

N0 = N
N1 = N0^3 mod 1000
N2 = N1^3 mod 1000
N3 = N2^3 mod 1000
...

看来 if N = 123, thenN19 = 947很容易计算三次根。有可能证明这个过程会给我们一个答案(Stack Overflow 站点不适合做证明,所以相信我或在Math Overflow上提问)。这个过程并不明显比其他任何过程都快,但它似乎已经足够快了;据我了解,它应该比蛮力方法更快,并进行了许多改进。

一些代码(基于原始代码):

while(1)
{
    c = j * j * j % s;
    if (c == p)
       break;
    j = c;
}

注意:这假设计算j * j * j不会溢出(小于 2^63)。这对于N最多 6 位数字来说已经足够了,这可能不够好,也可能不够好。

于 2013-10-19T22:18:41.197 回答