-3

1、3、7、または 9 で終わる数値 N を指定します。

3 乗すると同じ元の数 N で終わる数 M が常に存在します。M の桁数が N より多い必要はありません。

例: - N=123。M=947。(947)^3=849278123. ここで (947)^3 は N(123) で終わります。

入力として N を取り、M を見つけるプログラムを作成します。ここで、M は N とほぼ同じ桁数であり、3 乗すると 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回回った後)-Mを1回だけ見つけるのに約20マイクロ秒です...注-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 に答える
0

数値 N を取り、その 3 乗 (モジュロ 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 より小さい)ことを前提としています。これは 6 桁までは十分ですNが、これで十分である場合とそうでない場合があります。

于 2013-10-19T22:18:41.197 に答える