程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 1844 Sum[簡單數學]

POJ 1844 Sum[簡單數學]

編輯:C++入門知識

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 9795   Accepted: 6406

Description

Consider the natural numbers from 1 to N. By associating to each number a sign (+ or -) and calculating the value of this expression we obtain a sum S. The problem is to determine for a given sum S the minimum number N for which we can obtain S by associating signs for all numbers between 1 to N.

For a given S, find out the minimum value N in order to obtain S according to the conditions of the problem.

Input

The only line contains in the first line a positive integer S (0< S <= 100000) which represents the sum to be obtained.
Output

The output will contain the minimum number N for which the sum S can be obtained.
Sample Input

12Sample Output

7Hint

The sum 12 can be obtained from at least 7 terms in the following way: 12 = -1+2+3+4+5+6-7.
Source

Romania OI 2002


思路:

算是很簡單的數學題目了,但是昨天晚上就算幾乎是推出了規律,居然都沒有折騰出來太弱了。

然後完賽後在群裡和 TeilWall 吐槽了下,就差淚奔了。。。

 


正解思路:

 


先定義 sum(i) = 1+2+...+i = (i+1)*i/2 【小學數學。。。(首項+末項)*項數/2 了解Orz】

可想而知 sum(i) 是 i 能確定的最大的數。

 


1.對於每一個輸入的數 S ,我們找符合條件的 i 肯定是可以從 sum(i) >= S 開始枚舉 i 的。

  分析:如果連 sum(i) < S 那麼 i 肯定是不符合條件的了。

  PS:昨晚我在草稿紙上是逆推的,結果搞的很復雜,也沒有注意到從 sum(i) >= S 這裡開始枚舉。。。

 


2. 當我們由第一步確定了 i 後有兩種情況:

   (1)Sum(i) == S ,那麼很明顯 i 就是答案,直接輸出即可。

   (2)Sum(i) > S , 從 i 開始,依次往後面 +1 枚舉 ,只要遇到 (Sum(i) - S) % 2 == 0 輸出答案就可以了。

      其實 0%2 == 0 所以第一類情況實際上是可以歸類於第二種情況的了。

   分析:

        情況一已經很明顯了,下面主要分析情況二。。。

        對於每一個 i 能夠確定的數:

           很明顯最大的是 Sum(i) ,

           然後再把序列 1,2,3,...i 中的 + 依次改成 - 那麼能確定的下一個數一定比前一個數小二

           比如說 i = 3, 那麼能夠確定的數是 6 ,4 ,2 ,(1)

                  i = 4,  能確定的數是 10, 8, (6)

                  i = 5, 能確定的數是 15,13,11,9,7,5, (3)

           這裡有一個問題:如何確定能確定的最後一個數在哪裡截止, 如果減到後面遇的數已經被前面的數確定過,那麼就不用往後

                           面減了,由於前面已經提到了,我們是從前面往後面枚舉的 i 所以就不用考慮到哪裡截止的問題了。

           那麼從這裡可以看出:

                對於一個數 i 它能確定的最大的數是 Sum(i),

                如果對於當前的 i 它能夠確定當前的 S ,那麼 Sum(i)-S 一定是二的倍數。【(Sum(i)-S) % 2 == 0】

 


           因為我們是從最小的可能滿足條件的 i 開始枚舉的,所以不會出現前面的 i 滿足條件而小於當前的 i 的情況。

           也就是說一旦遇到了 (Sum(i)-S)%2 == 0 輸出 i 就可以了。

 


我比賽時的想法分析:

 


當時我已經在草稿紙上畫出了下面的東東了。。。

 

 

 

 


但是我居然是逆推的,同時沒想過枚舉。。。而且這麼明顯的結論也沒有看出來,然後我就推出了下面的復雜而傻逼的公式。。。

 


如果結尾的數 N 是偶數:

那麼 N 可以確定的數是從 (1+N)*N/2 開始 依次減二 直到大於 (1+ N-1)*(N-1)/2 為止

如果結尾的數 N 是奇數:

那麼 N 可以確定的數是從 (1+N)*N/2 開始 依次減二 知道大於 (1+ N-2)*(N-2)/2 為止

。。。。

然後實在是無法逆推出直接的公式了,也想到過枚舉,但是開始沒想到枚舉的區間從哪裡開始

然後看做這題無望,時間已經過去了大半,就果斷去寫了前面簡單的貪心。。。一直自認為關於找規律還是很在行的了,結果還是坑在了這題上。

 

code:

#include<stdio.h>

const int maxn = 100000;

int main()
{
    int s;
    while(scanf("%d", &s) != EOF)
    {
        int sum = 0;
        int i;
        for(i = 1; i < maxn; i++) //先找到和 <= 自己的最小的數
        {
            sum = (1+i)*i/2;
            if(sum >= s) break;
        }
        int index = i; //記錄

        for(;;)
        {
            sum = (1+index)*index/2;
            if((sum-s)%2 == 0) //往後面找, 只要找到就輸出
            {
                printf("%d\n", index);
                break;
            }
            index++;
        }
    }
    return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved