[문제해결] 비밀번호486 조언 부탁드립니다...(한달째 고민하고 있습니다)

  • gloryof11
    gloryof11

    멋진 조언 덕분에 문제 해결하였습니다!
    감사합니다.
    (첨부된 코드는 시간초과되는 코드라 그냥 놔두었습니다.)


    안녕하세요. 비밀번호486문제로 매일집중하지는 못했지만, 거의 한달정도 꾸준히 고민하고 있는 알고리즘 초보 입니다.. (어제 인터넷으로 책 구입신청했습니다..)
    좀 부족한 코드이지만, 아래 제 코드가 시간초과 안되고 5000 ms 이내로 들어올 가능성이 있을지 의견을 듣고 싶어 글을 올립니다.
    고수님들의 조언 부탁드립니다.
    감사합니다.

    비밀번호486

    #include <stdio.h>
    #include <time.h>
    
    int TC;
    int num,lo,hi;
    int memo[10000001];
    int prime[3163];
    int primenb = -1;
    int cnt,ea,temp,result;
    
    int main(void)
    {
    time_t st = clock();
    
        // find prime num up to sqrt(10,000,000)
        for(int i=2;i<3163;i++) {
            cnt = 0;
            for(int j=2;j<=i;j++) {
                if(i%j == 0) cnt++;
                if(cnt==2) goto next1;
            }
            if(cnt == 1) {
                memo[i] = 2;
                prime[++primenb]=i;
            }
    next1:;
        }
        memo[1] = 1;
    
        //scanf("%d",&TC);
        TC=1;
        for(int i=0;i<TC;i++)
        {
            //scanf("%d %d %d",&num,&lo,&hi);
            num = 200; lo = 1; hi = 10000000;
            // find divisor num
            for(int j=lo;j<=hi;j++)
            {
                if(memo[j] != 0)
                    continue;
                temp = j;
                cnt = 1;
    
                for(int k=0;k<primenb;k++)
                {
                    ea = 1;
                    while(temp%prime[k]==0)
                    {
                        temp = temp/prime[k];
                        ea++;
                    }
                    if(ea==1) continue;
    
                    cnt = cnt*ea;
                    if(temp == 1 || memo[temp] == 2) {
                        memo[j]=cnt*memo[temp];
                        goto next2;
                    }
                }
    
                memo[temp] = 2;
    
                if(ea==1)
                    memo[j]=cnt*memo[temp];
                else
                    memo[j]=cnt;
    
        next2:;
            }
    
            for(int j=lo;j<=hi;j++)
            {
                if(memo[j] == num) result++;
            }
            printf("%d\n",result);
    
            result = 0;
        }
    printf("time : %d\n",clock()-st);
        return 0;
    }
    


    11년 전
4개의 댓글이 있습니다.
  • 일루
    일루

    우선 소수가 빨리 구해지는지 의문이네요. 그 부분이 느리다면 에라토스테네스의 체로 바꿔보세요.

    그러면 아래쪽 메인 로직과 겹치는 부분이 보이실 겁니다.


    11년 전 link
  • kcm1700
    kcm1700

    몇가지 힌트를 적어드리는 게 좋을 것 같아서 적어봅니다.

    만약 입력으로 들어온 테스트케이스에 겹치는 구간이 있다면 굳이 매번 계산할 필요가 있을까요?


    에라토스테네스의 체는 꽤 빠릅니다. 시간복잡도 분석을 직접 해보시거나 검색해보세요. 그에 비해 sqrt까지 나눠보는 건 느립니다.


    약수가 존재한다면 아무 약수나 빠르게 찾을 수 있을까요?


    11년 전 link
  • kriii
    kriii

    음 메모이제이션은 하신 것 같은데 메모이제이션을 하기 위한 값을 구하는게 느린것 같아보입니다.

    54 = 2^3 * 3^2 이므로, 3^2 = 9의 약수의 개수를 안다면 54의 약수의 개수는 쉽게 구할수 있지 않을까요??


    11년 전 link
  • gloryof11
    gloryof11

    일루 님, kcm1700 님, kriii 님 모두모두 감사드립니다!
    책은 받았지만, 보지않고 주신 힌트로만 문제 해결할 수 있었습니다.
    공짜로 배우기에 죄송할 정도의 도움을 주셔서 감사드립니다 ^^
    좋은 하루 보내세요!
    (알고리즘 전문가는 정말 유연한 사고를 가져야 하는 것 같네요^^;)


    11년 전 link
  • 정회원 권한이 있어야 커멘트를 다실 수 있습니다. 정회원이 되시려면 온라인 저지에서 5문제 이상을 푸시고, 가입 후 7일 이상이 지나셔야 합니다. 현재 문제를 푸셨습니다.