簡體   English   中英

需要解釋此代碼

[英]Need Explanation of this code

代碼輸出滿足條件的(i,j)對的數量

(2^j-1) % (2^i-1) == 0

在哪里

1<=i<j<=n

n是用戶輸入的數字,在該數字下將找到(i,j)對的數量。 代碼工作得很好,但這段代碼背后的邏輯很難理解。

PS:t是一個變量,它允許用戶一次輸入多個數字。

    #include<stdio.h>
    #include<math.h>
    int main()
    {   
        int t;
        long n,sum,ans; 
        scanf("%d",&t);
        while(t--)
        {
            scanf("%ld",&n);
            int nrt=(int)sqrt(n);
            sum=0;
            for(int i=1;i<=nrt;i++)
            {
                 sum+=n/i;
            }
            ans=2*sum-nrt*nrt-n;
            printf("%ld\n",ans);
        }
    return 0;
    }

讓我們采用蠻力的方法解決問題並打印結果*:

 #############################   2^^1 -1 == 1
  -#-#-#-#-#-#-#-#-#-#-#-#-#-#   2^^2 -1  == 3
   --#--#--#--#--#--#--#--#--#   2^^3 -1  == 7
    ---#---#---#---#---#---#--   2^^4 -1  == 15
     ----#----#----#----#----#   2^^5 -1  == 31
      -----#-----#-----#-----#   2^^6 -1  == 63
       ------#------#------#--   2^^7 -1  == 127
        -------#-------#------   2^^8 -1  == 255
         --------#--------#---   2^^9 -1  == 511
          ---------#---------#   2^^10 -1 == 1023
           ----------#--------   2^^11 -1 == 2047
            -----------#------   2^^12 -1 == 4095
             ------------#----   2^^13 -1 == 8191
              -------------#--   2^^14 -1 == 16383
               --------------#   2^^15 -1 == 32767
                --------------   2^^16 -1 == 65535
                 -------------   2^^17 -1 == 131071
                           ...   ...

哈希標記表示滿足條件的情況。 一個很好的模式出現了:你的每個數字都可以被1整除,每個數字都可以被3整除,每三個數字可被7整除,依此類推。 i個數為整除2^^i - 1 。**

有了這種洞察力,我們可以將您的功能編碼為:

int f(int n)
{
    int sum = 0;
    int i;

    for (i = 1; i <= n; i++) sum += (n - i) / i;

    return sum;
}

我們可以用n / i - 1代替(n - i) / i並將公共子標記-1移動到返回值中:

int g(int n)
{
    int sum = 0;
    int i;

    for (i = 1; i <= n; i++) sum += n / i;

    return sum - n;
}

現在讓我們看一下和∑(1, n: n / i) 例如:

∑(i = 1, 9: 9 / i) = 9 + 4 + 3 + 2 + 1 + 1 + 1 + 1 + 1

我們可以通過從右到左查看它並計算每個summand出現的頻率來獲得相同的總和:

∑(i = 1, 9: 9 / i) = 5*1 + 1*2 + 1*3 + 1*4 + 1*9

我們可以輕松獲得這種表示:

∑(i = 1, n: n / i) = ∑(1, n: i * (n / i - n / (i + 1))

這真的只是寫這筆錢的另一種方式; 你可以通過不同的方式對summands進行分組,以便它們共享相同的分母:

∑(i = 1, N: i * (n / i - n / (i + 1))
    = n + ∑(i = 1, n: ((i + 1) - i)  * n / (i + 1))
    = n + ∑(i = 1, n: n / (i + 1)) - (N + 1) * (n / (N + 1))
    = n + ∑(i = 2, n + 1: n / i) - c
    = ∑(i = 1, n: n / i) - c

附加項c = (N + 1) * (n / (N + 1))是校正項,因為僅使用i = n + 1項的一半。 當在整個范圍內求和時, n / (n + 1)為零並消失。 當僅對數組的一部分求和時,它不會消失,我們稍后會看到。

如果我們在s = sqrt(n)處將總和分成頭部和尾部,我們得到:

∑(i = 1, n: n / i) = ∑(i = 1, s: n / i) + ∑(s + 1, n: n / i)

讓我們以原始的方式表示頭部,並以“計數加數”的方式表示尾部,例如:

∑(i = 1, 9: 9 / i) = (9 + 4 + 3)   +   (5*1 + 1*2)

對於任何n

∑(i = 1, n: n / i) 
    = ∑(i = 1, s: n / i) + ∑(1, s - 1: i * (n / i - n / (i + 1))
    = ∑(i = 1, s: n / i) + ∑(1, s: n / i) - s * (n / s)

所有的除法都是整數除法(這就是為什么有時必須有括號)和n / s == s ,所以:

∑(1, n: n / i) = ∑(i = 1, s: n / i) + ∑(i = 1, s: n / i) - s * (n / s)
               = 2 * ∑(i = 1, s: n / i) - s²

這產生了你原來的功能:

int h(int n)
{
    int nrt = sqrt(n);
    int sum = 0;
    int i;

    for(i = 1; i <= nrt; i++) sum += n/i;

    return 2 * sum - nrt * nrt - n;
}

其中上面g中的∑(1, n: n / i)已經用2 * ∑(i = 1, s: n / i) - s²代替。

*)我在這里偷了D的力量算子 ^^ ,以免混淆以面值取^的舊C buff,即xor。

**)我不知道, 為什么模式顯示。 可能有一個很好的解釋,但就目前而言,我相信我的模式匹配技能。 盲目。 編輯 @ nevets的答案有這種模式的解釋。

這是一個非常有趣的問題。 如果您嘗試了一些小輸入,您將對代碼有一個大致的了解。

n = 10 ,我使用一個非常簡單的代碼生成所有有效對,這是我得到的:

1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
2 4
2 6
2 8
2 10
3 6
3 9
4 8
5 10

驚喜? 我們在這里可以看到一個非常明顯的模式:當i, j滿足j = k * i ,其中k是整數, j = k * i < ni, j是有效對。 它與原始方程完全無關,僅取決於n

實際上這並不奇怪, 因為 (2^(nk) - 1) = ((2^k)^n - 1) = (a^n - 1) ,其中a = 2^k因此我們可以應用分解規則給出(a^n - 1) = (a - 1)(a^(n - 1) + a^(n - 2) + .. + 1) ,因此可以通過(a - 1)分解,即(2^(nk) - 1) % (2^k - 1) == 0

現在問題變成如何有效地計算這個數字。 根據條件,我們有j > i 以前我們知道j = k * i 因此, k必須在[2, n / i]的范圍內。 對於每個i ,我們有完全(n / i) - 2 + 1 = (n / i) - 1有效的k選擇。 因此,總有效對將是sigma((n / i) - 1, 1 <= i <= n)

至於如何將等式轉換為您給出的代碼,請參閱@ MOehm的答案。

變量i從1到nrt工作,nrt是n的平方根, converted explicitily into an int value 每次循環工作時,sum都會被(n / i)的結果相加。 然后代碼打印ans (長類型),計算為(sum-nrt square-n的兩倍)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM